g++ 和 clang++ 具有指向可变参数模板函数的指针的不同行为
g++ and clang++ different behaviour with pointer to variadic template functions
C++ 标准专家的另一个 "who's right between g++ and clang++ ?" 问题。
代码如下
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
}
模板函数 foo()
接收可变模板参数 bar
。
第一次通话
foo<int>(bar<int, long>{}); // g++ and clang++ compile
适用于 clang++ 和 g++。
如果我理解正确的话,foo<int>
被解释为 只有 第一个模板参数并且这没有完成 Ts...
参数列表。所以编译器查看参数(一个 bar<int, long>
对象)并推导出完整列表。
第二次调用不同
(*(&foo<int>))(bar<int, long>{}); // g++ and clang++ give error
如果我理解正确的话,使用 (&foo<int>)
我们得到指向 foo
实例化的指针,其中 Ts...
正好是 int
(不仅是第一种列出但整个列表)并取消引用它(*(&foo<int>)
)并使用错误的参数调用它(bar<int, long>
对象)我们得到(clang++ 和 g++)编译错误。
到目前为止,还不错。
第三次调用出现问题
(&foo<int>)(bar<int, long>{}); // clang++ compiles; g++ gives error
我确信(也许我错了)第二个(我们修复了 Ts...
中的所有模板类型,然后我们用错误的参数调用函数)但是 g++ 似乎同意(并给出错误) 其中 clang++ 不同意(并且编译没有问题)。
像往常一样,问题是:谁是对的?
让我们来看一个更简单的案例:
template <class A, class B>void foo(B) {};
int main()
{
(&foo<char>)(1);
}
clang++ 编译它,而 g++ 失败并显示以下消息:
error: address of overloaded function with no contextual type information
同样的消息是针对例如这个程序:
void moo(int) {};
void moo(int*){};
int main()
{
&moo != nullptr;
}
显然,其意图是参考 [over.over],其中讨论了获取重载函数的地址。标准中的这个地方指定了在什么上下文中可以使用重载函数名称(赋值的 RHS,函数调用中的参数等)。然而它说
An overloaded function name shall not be used without arguments in contexts other than those listed. (emphasis mine)
现在,(&foo<char>)(1)
中的 foo
是否使用了 无参数 ? g++ 好像就这么沉了。但是它很高兴编译
(&moo)(1);
来自第二个例子。所以我们在这里至少有一些不一致。获取函数模板和重载集的地址的规则相同,因此 (&foo<char>)(1)
和 (&moo)(1)
应该都有效或都无效。该标准本身似乎表明嘿应该都是有效的:
The overloaded function name can be preceded by the & operator [...] [Note: Any redundant set of parentheses surrounding the overloaded function name is ignored (5.1). — end note]
C++ 标准专家的另一个 "who's right between g++ and clang++ ?" 问题。
代码如下
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
}
模板函数 foo()
接收可变模板参数 bar
。
第一次通话
foo<int>(bar<int, long>{}); // g++ and clang++ compile
适用于 clang++ 和 g++。
如果我理解正确的话,foo<int>
被解释为 只有 第一个模板参数并且这没有完成 Ts...
参数列表。所以编译器查看参数(一个 bar<int, long>
对象)并推导出完整列表。
第二次调用不同
(*(&foo<int>))(bar<int, long>{}); // g++ and clang++ give error
如果我理解正确的话,使用 (&foo<int>)
我们得到指向 foo
实例化的指针,其中 Ts...
正好是 int
(不仅是第一种列出但整个列表)并取消引用它(*(&foo<int>)
)并使用错误的参数调用它(bar<int, long>
对象)我们得到(clang++ 和 g++)编译错误。
到目前为止,还不错。
第三次调用出现问题
(&foo<int>)(bar<int, long>{}); // clang++ compiles; g++ gives error
我确信(也许我错了)第二个(我们修复了 Ts...
中的所有模板类型,然后我们用错误的参数调用函数)但是 g++ 似乎同意(并给出错误) 其中 clang++ 不同意(并且编译没有问题)。
像往常一样,问题是:谁是对的?
让我们来看一个更简单的案例:
template <class A, class B>void foo(B) {};
int main()
{
(&foo<char>)(1);
}
clang++ 编译它,而 g++ 失败并显示以下消息:
error: address of overloaded function with no contextual type information
同样的消息是针对例如这个程序:
void moo(int) {};
void moo(int*){};
int main()
{
&moo != nullptr;
}
显然,其意图是参考 [over.over],其中讨论了获取重载函数的地址。标准中的这个地方指定了在什么上下文中可以使用重载函数名称(赋值的 RHS,函数调用中的参数等)。然而它说
An overloaded function name shall not be used without arguments in contexts other than those listed. (emphasis mine)
现在,(&foo<char>)(1)
中的 foo
是否使用了 无参数 ? g++ 好像就这么沉了。但是它很高兴编译
(&moo)(1);
来自第二个例子。所以我们在这里至少有一些不一致。获取函数模板和重载集的地址的规则相同,因此 (&foo<char>)(1)
和 (&moo)(1)
应该都有效或都无效。该标准本身似乎表明嘿应该都是有效的:
The overloaded function name can be preceded by the & operator [...] [Note: Any redundant set of parentheses surrounding the overloaded function name is ignored (5.1). — end note]