我希望有一个函数将参数限制为仅来自特定模板化类的类型。在这种情况下,basic_string
(来自STL - docs)。例如,声明wstring
:
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。
答案 0 :(得分:10)
有三种方法可以解决您的问题,一种是is_specialization_of
的实现,另一种是让您的函数采用std::basic_string<T1,T2,T3>
代替TString
,第三种方法是与第二种解决方案相同的理念;使模板仅由std::basic_string
匹配。
is_base_of
在您的示例中是不够的,原因有两个:
is_base_of
用于查看类型U
是否来自T
(或者如果它是相同的类型),在您的代码段中不涉及继承。
std::basic_string
不是完整类型,因此根本不能与is_base_of
一起使用(您已经指出过)。
解决方案#1
is_specialization_of
将用于检查类型U
是否为不完整类型T
的特化。使用模板模板类实现它非常容易,如下例所示。
使用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