max*_*x66 12 c++ templates variadic-templates c++11 template-argument-deduction
另一个"g ++和clang ++之间谁是正确的?" C++标准大师的问题.
代码如下
template <typename ...>
struct bar
{ };
template <typename ... Ts>
void foo (bar<Ts...> const &)
{ }
int main ()
{
foo<int>(bar<int, long>{}); // g++ and clang++ compile
(*(&foo<int>))(bar<int, long>{}); // g++ and clang++ give error
(&foo<int>)(bar<int, long>{}); // clang++ compiles; g++ gives error
}
Run Code Online (Sandbox Code Playgroud)
模板函数foo()接收可变参数模板参数bar.
第一个电话
foo<int>(bar<int, long>{}); // g++ and clang++ compile
Run Code Online (Sandbox Code Playgroud)
适用于clang ++ ang g ++.
如果我理解正确,与foo<int>被阐明只有第一个模板参数,这没有完成的列表Ts...参数.因此编译器会查看参数(bar<int, long>对象)并推导出完整列表.
第二个电话是不同的
(*(&foo<int>))(bar<int, long>{}); // g++ and clang++ give error
Run Code Online (Sandbox Code Playgroud)
如果我理解正确的话,与(&foo<int>)我们得到的指针的实例foo,其中Ts...恰好是int(不仅是第一种类型列表中,但整个列表)和取消引用它(*(&foo<int>)),用错误的参数调用它(bar<int, long>对象),我们得到( clang ++和g ++)编译错误.
到现在为止还挺好.
问题出现在第三次电话会议上
(&foo<int>)(bar<int, long>{}); // clang++ compiles; g++ gives error
Run Code Online (Sandbox Code Playgroud)
我确信(也许我错了)等同于第二个(我们修复了所有模板类型Ts...,然后我们用错误的参数调用函数)但g ++似乎同意(并给出错误)clang ++不同意(并且编译没有问题) .
像往常一样,问题是:谁是对的?
让我们看一个更简单的情况:
\n\ntemplate <class A, class B>void foo(B) {};\n\nint main()\n{\n (&foo<char>)(1);\n}\nRun Code Online (Sandbox Code Playgroud)\n\nclang++ 编译它,而 g++ 失败并显示以下消息:
\n\n\n\n\n错误:重载函数的地址没有上下文类型信息
\n
例如,该程序给出了相同的消息:
\n\nvoid moo(int) {};\nvoid moo(int*){};\n\nint main()\n{\n &moo != nullptr;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n显然,其意图是引用 [over.over],它讨论了获取重载函数的地址。标准中的这个位置指定了可以在哪些上下文中使用重载函数名称(赋值的右侧、函数调用中的参数等)。然而它说
\n\n\n\n\n在未列出的上下文中,不得在没有参数的情况下使用重载函数名称。(强调我的)
\n
现在,使用foo时不带参数吗?g++ 似乎就这么沉下去了。然而它很高兴编译(&foo<char>)(1)
(&moo)(1);\nRun Code Online (Sandbox Code Playgroud)\n\n从第二个例子来看。所以我们这里至少有一些不一致之处。相同的规则管理获取函数模板和重载集的地址,因此(&foo<char>)(1)和(&moo)(1)应该要么都是有效的,要么都是无效的。标准本身似乎表明 hey 应该都是有效的:
\n\n重载函数名称前面可以加上 & 运算符 [...] [注意:重载函数名称周围的任何多余括号都将被忽略 (5.1)。\xe2\x80\x94尾注]
\n