4

我想要一个函数,将参数限制为仅从特定模板类派生的类型。在这种情况下,basic_string(来自 STL文档)。例如,wstring声明了 a:

typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >
wstring;

基本的想法是这样的:

template <class TString>
void strings_only_please(TString message) {
    static_assert(is_base_of<basic_string, TString>::value, 
        "Not a string type!");  
}

当然,虽然没有指定 basic_string ,但它不会编译......它需要一个真实的类型。(虽然我可能只对少数实际的字符串类型进行硬编码,但我正在寻找这种模式的通用解决方案。)

我正在使用 Visual Studio 2012,理想情况下希望代码可移植到其他现代 C++ 编译器,如 GCC。

4

1 回答 1

10

有三种方法可以解决您的问题,一种是 的实现is_specialization_of,另一种是让您的函数采用 astd::basic_string<T1,T2,T3>而不是TString,第三种方法与第二种解决方案具有相同的理念;使模板只能由std::basic_string.


is_base_of由于两个原因,在您的示例中还不够:

  1. is_base_of用于查看类型U是否派生自T(或是否为同一类型),在您的代码段中不涉及继承。

  2. std::basic_string不是一个完整的类型,因此根本不能使用is_base_of(您已经指出)。


解决方案#1

is_specialization_of将用于检查 type 是否U不完整类型的特化T。使用模板模板类很容易实现它,如下例所示。

正如@SebastianRedl 所指出的,可变参数模板不适用于VS2012,请参阅其他解决方案(它们不是通用的,但仍足以满足您的需求)。

#include <type_traits>
#include <iostream>
#include <string>

template<template<typename...> class T, typename U>
struct is_specialization_of              : std::false_type { };

template<template<typename...> class T, typename... Ts> 
struct is_specialization_of<T, T<Ts...>> : std::true_type  { };

int
main (int argc, char *argv[])
{
  std::cerr << is_specialization_of<std::basic_string, std::string >::value << std::endl;
  std::cerr << is_specialization_of<std::basic_string, std::wstring>::value << std::endl;
  std::cerr << is_specialization_of<std::basic_string, std::istream>::value << std::endl;
}

输出

1
1
0

解决方案#2

template <typename T1, typename T2, typename T3>
void strings_only_please(std::basic_string<T1,T2,T3>) {
  // ...  
}

当然,上述内容不会导致static_assert错误 - 但它足以满足您的需求并满足您的需求;该函数只能由专门的类型调用std::basic_string


解决方案#3

template<typename T>
struct is_basic_string : std::false_type { };

template<typename T1, typename T2, typename T3>
struct is_basic_string<std::basic_string<T1,T2,T3>> : std::true_type { };

...

is_basic_string<std::string >::value // true
is_basic_string<std::istream>::value // false
于 2013-07-10T15:17:20.800 回答