MiC*_*Cha 5 c++ templates sfinae c++11
为什么我必须::type = 0在这种std::enable_if用法中使用默认值( )?
我看到一些例子,没有它也能工作。例如https://foonathan.net/blog/2015/11/30/overload-resolution-4.html
\n\n#include<iostream>\n#include<type_traits>\n\ntemplate <typename T,\n typename std::enable_if<std::is_integral<T>::value, T>::type = 0>\nvoid do_stuff(T t) {\n std::cout << "do_stuff integral\\n";\n}\n\ntemplate <typename T,\n typename std::enable_if<std::is_class<T>::value, T>::type = 0>\nvoid do_stuff(T t) {\n std::cout << "do_stuff class\\n";\n}\n\nint main()\n{\n do_stuff(32);\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我收到错误消息:
\n\ntemp.cpp:6:6: note: template argument deduction/substitution failed:\ntemp.cpp:18:13: note: couldn\'t deduce template parameter \xe2\x80\x98<anonymous>\xe2\x80\x99\nRun Code Online (Sandbox Code Playgroud)\n\n应推论为
\n\ntemplate <template T, int>\nvoid do_stuff(T t)\nRun Code Online (Sandbox Code Playgroud)\n\n这是有效的代码。\n我做错了什么?(海湾合作委员会版本7.4.0)
\n编译器清楚地告诉您问题是什么:在模板声明中,您指定了一个无法推导的额外模板非类型参数。您期望编译器如何推断出该非类型参数的正确值?从何而来?
这正是上述使用技术std::enable_if需要默认参数的原因。这是一个虚拟参数,因此默认参数值并不重要(这0是一个自然的选择)。
您可以将示例简化为
template <typename T, T x>
void foo(T t) {}
int main()
{
foo(42);
}
Run Code Online (Sandbox Code Playgroud)
生产
error: no matching function for call to 'foo(int)'
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter 'x'
Run Code Online (Sandbox Code Playgroud)
编译器可以推断出T( T == int) 是什么,但编译器无法推断出 的参数x。
您的代码完全相同,只是您的第二个模板参数未命名(无需为虚拟参数命名)。
从您的评论来看,您似乎对代码中第二个参数的声明中存在关键字感到困惑typename,这使您相信第二个参数也是类型参数。后者是不正确的。
请注意,第二个参数的声明关键字typename用于完全不同的角色。这个关键字只是消除了语义的歧义
std::enable_if<std::is_class<T>::value, T>::type
Run Code Online (Sandbox Code Playgroud)
它告诉编译器嵌套名称实际上代表类型type的名称,而不是其他名称。(您可以在此处阅读有关此用法的信息:Why do we need typename here?以及Where and Why do I have to put the "template" and "typename" keywords?)typename
这种用法typename不会将模板的第二个参数转换为类型参数。模板的第二个参数仍然是非类型参数。
这是另一个简化的示例,说明了代码中发生的情况
struct S { typedef int nested_type; };
template <typename T, typename T::nested_type x>
void bar(T t)
{}
int main()
{
S s;
bar<S, 42>(s);
}
Run Code Online (Sandbox Code Playgroud)
请注意,即使第二个参数的声明以 a 开头typename,它仍然声明一个非类型参数。
| 归档时间: |
|
| 查看次数: |
1167 次 |
| 最近记录: |