为什么即使模板类型被声明为“类”,“类型名”仍然是必需的
Why is `typename` still necessary even the template type is declared as `class`?
#include <type_traits>
using namespace std;
template<class T> struct IsCharType { enum { value = false }; };
template<> struct IsCharType<char> { enum { value = true }; };
template<> struct IsCharType<wchar_t> { enum { value = true }; };
template<class CharType, class = enable_if<IsCharType<CharType>::value>::type>
struct MyString
{
MyString()
{}
MyString(CharType*)
{}
};
template<class CharType>
MyString<CharType> GetMyString(CharType* str) // error C2923
{
return MyString<CharType>(str);
}
int main()
{}
我的编译器是VC++ 2013 RC。由于错误 C2923,无法编译上面的代码。
错误 C2923:"我的字符串": 'std::enable_if::value,void>::type' 不是有效的 参数 '' 的模板类型参数
但是,如果我改变
template<class CharType, class = enable_if<IsCharType<CharType>::value>::type>
自
template<class CharType, class = typename enable_if<IsCharType<CharType>::value>::type>
那就没事了。
我只是想知道为什么这里需要typename
?在这种情况下,我有两个原因:
编译器可以推断第二个模板参数是否为类型名称;因为我把它贴花为
class
.即使编译器无法推断它是否为类型名称,根据
SFINAE
规则,编译器也不应失败,因为未调用模板函数GetMyString
。
您尚未将其声明为类。模板参数声明
class = enable_if<IsCharType<CharType>::value>::type
是未命名类型参数的声明。我们可以给这个参数一个显式的名称,例如
class U = enable_if<IsCharType<CharType>::value>::type
因此,在这种情况下,U
声明为类型参数("asclass")。
同时,=
右边的一切都没有"宣布为阶级"。编译器根据一般规则解释它,而不考虑它恰好是类型参数的默认参数这一事实。
像"由于这是类型参数的默认参数,编译器必须自己意识到这是一个类型"这样的逻辑在这里不适用,因为语言规范没有说它适用。此外,语言标准实际上说
模板声明或定义中使用的名称,即 依赖于模板参数假定不命名类型,除非 适用的名称查找查找类型名称或名称是限定的 通过关键字类型名称。
这意味着编译器需要假设
enable_if<IsCharType<CharType>::value>::type
不是一个类型,这与你期望它做的事情相反。
该语言确实有许多上下文,其中无条件地假定依赖名称来命名类型。这包括构造函数初始值设定项列表、基类说明符和详细的类型说明符。但模板类型参数的默认参数不是此类上下文之一。
SFINAE并没有在这里挽救这种情况。顾名思义,SFINAE 在替换时起作用。你的代码永远不会被替换,它会更早地中断。它只是一个无效的模板定义。
- 将依赖名称显式标记为类型名和模板的奇怪之处
- <Windows>为什么 std::thread::native_handle 返回类型为"long long unsigned int"的值,而不是 void*(又名 HANDLE)?
- 具有条件类型名的模板类
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何检测类型类型别名?
- 在模板中使用类型类型的类型类型使用模板类别IT自我
- 具有枚举类型类型的C 方法
- qmetatype ::类型从模板类型类型
- C 线程错误:无类型类型
- C++ 类型(类型名称)上的问题
- 确定类型类型
- 函数指针类型(F)(类型)和类型(类型)(类型)(类型)之间的差异
- C/C++中的"#define AP_MODULE_DECLARE(类型)类型"
- 类型“类名”不提供调用运算符.C++
- 为什么我们需要依赖于 C++ 中的模板参数的类型类型名
- C++提升错误:无法在初始化中将常量值类型*(又名常量 wchar_t*)转换为常量字符*
- 函数常量返回类型:类型引用的初始化无效
- 特征类型类型定义失败,并显示 C4430
- 复合赋值运算符的类型/类型转换?(例如*=(星形等于))
- 带有模板的类型类型