Ted*_*ton 19 c++ templates iostream endl
考虑以下短节目。
\n#include <iostream>\n\ntemplate< typename ... Ts >\nclass foobar\n{\n static_assert( sizeof...(Ts) > 0 );\n};\n\ntemplate< typename ... Ts >\nstd::ostream& operator<<( std::ostream& o, const foobar< Ts... >& )\n{\n return o;\n}\n\nint main(void)\n{\n std::cout << "This has nothing to do with foobar" << std::endl;\n}\n
Run Code Online (Sandbox Code Playgroud)\n当我们尝试编译这个时,我们得到......
\nted@tedscomputer:~/Projects/emptypack$ g++ -o emptypack main.cpp\nmain.cpp: In instantiation of \xe2\x80\x98class foobar<>\xe2\x80\x99:\nmain.cpp:17:63: required from here\nmain.cpp:6:34: error: static assertion failed\n 6 | static_assert( sizeof...(Ts) > 0 );\n | ~~~~~~~~~~~~~~^~~\nted@tedscomputer:~/Projects/emptypack$\n
Run Code Online (Sandbox Code Playgroud)\n我知道这std::endl
有点奇怪(以至于它实际上有自己的 StackOverflow 标签),但是这里到底出了什么问题?为什么编译器尝试使用空类型参数实例化我完全不相关的类,失败,然后生成错误?
也许更重要的是,每次我编写一个带有参数包的类时,我是否必须确保它可以在没有类型参数的情况下实例化,即使这对程序逻辑没有任何意义,以防万一它在一英里之内std::endl
?
@Artyer 发现了这个:
\n\n\n\n... [注 1:尾随模板参数包 ... 未以其他方式推导将被推导为模板参数的空序列。\n\xe2\x80\x94 尾注]
\n
通常,如果您只是将特定类型的对象传递给第二个参数,则不满足条件:
\n::operator<<(std::cout, foobar<int>{}); // compiles\n
Run Code Online (Sandbox Code Playgroud)\n即使您传递不同类型的对象,仍然不满足条件:
\n// Causes `error: no matching function for call to \'operator<<\'`,\n// does NOT trigger the `static_assert`.\n::operator<<(std::cout, 0);\n
Run Code Online (Sandbox Code Playgroud)\n我认为这是因为编译器确实Ts...
尝试从参数类型推断并失败。
如果我们将参数拼写为std::enable_if_t<true, const foobar<Ts...> &>
,则总是满足条件,因为不可能Ts...
从中推断出,并且编译器甚至不会尝试。
但为什么我们的例子满足这个条件呢?因为std::endl
,作为函数模板(未指定模板参数)没有类型,因此不可能从中推断出任何内容。