在模板中经常碰见形如 typename = decltype(…) ,typename 后直接跟等于号 = ,而没有参数名字的情况。
在C++中,你可以在类成员中使用未命名的模板参数,形如 typename = decltype(…),以便于为模板提供默认值或者进行条件编译。以下是一个简单的示例:
#include <iostream>
template<typename T, typename = void>
class MyClass {
public:
void print() {
std::cout << "Primary template: " << typeid(T).name() << std::endl;
}
};
template<typename T>
class MyClass<T, typename std::enable_if<std::is_integral<T>::value>::type> {
public:
void print() {
std::cout << "Specialization for integral types: " << typeid(T).name() << std::endl;
}
};
int main() {
MyClass<float> obj1; // 使用主模板
obj1.print();
MyClass<int> obj2; // 使用特化模板
obj2.print();
return 0;
}
在这个示例中,我们定义了一个名为 MyClass
的模板类,它有两个模板参数,其中第二个是未命名的,并且设置了默认值为 void
。
We then specialize the template for integral types using SFINAE (Substitution Failure Is Not An Error) technique, where the second template parameter is only valid if T
is an integral type.
然后,我们定义了一个特化版本,只有在第一个模板参数 T
是整数类型时才会生效。
在每个类中,我们有一个成员函数 print()
,它会根据模板的类型打印不同的消息。
在 main()
函数中,我们实例化了两个 MyClass
对象,分别使用了 float
和 int
作为模板参数。由于 float
不是整数类型,所以 obj1
使用了主模板,而 int
是整数类型,所以 obj2
使用了特化模板。
在C++模板中,typename
后跟等于号 (=
) 用于给模板参数指定默认值。这意味着如果在使用模板时未显式提供该参数的值,则将使用默认值。
template<
typename S,
typename C = typename std::decay<S>::type,
typename = decltype(std::declval<C>().data()),
typename = typename std::enable_if<
std::is_same<typename C::value_type, char>::value
#ifdef _WIN32
|| std::is_same<typename C::value_type, wchar_t>::value
#endif
>::type
>
C
参数使用了typename std::decay<S>::type
作为默认值。这里std::decay
是一个模板元函数,它会将传入的类型进行 “腐化” 处理,去除引用、cv-限定符(const 和 volatile),从而得到一个纯净的类型。在这个模板中,它的作用是将S
类型进行处理,使其成为C
类型的默认值。- 第三个参数使用了
decltype(std::declval<C>().data())
作为默认值。std::declval
是一个模板函数,它返回一个可以用于表达所传递类型的临时值。decltype
返回表达式的类型。这里假设C
有一个名为data()
的成员函数,并将其类型作为默认值。 - 最后一个参数使用了
typename std::enable_if<...>::type
作为默认值。std::enable_if
是一个模板元函数,它根据模板参数的值决定是否定义了一个内部的成员类型type
。在这里,它用于使模板只在满足一定条件时才可用。条件是检查C::value_type
是否与char
相同,并且在_WIN32
宏被定义时,还检查它是否与wchar_t
相同。
这些默认值确保了模板在大多数情况下可以正常工作,并且只在特定条件下才会启用。