考虑以下计划:
#include <iostream>
template <typename T>
void foo(const T* x) {
x();
}
void bar() { std::cout<<"bar() is called\n"; }
int main() {
foo(bar);
}
它在clang++
&amp; VC++
但是g++
会出现以下编译错误(请参阅实时演示here)
main.cpp: In function 'int main()':
main.cpp:10:9: error: no matching function for call to 'foo(void (&)())'
foo(bar);
^
main.cpp:3:6: note: candidate: template<class T> void foo(const T*)
void foo(const T* x) {
^~~
main.cpp:3:6: note: template argument deduction/substitution failed:
main.cpp:10:9: note: types 'const T' and 'void()' have incompatible cv-qualifiers
foo(bar);
^
我在使用-pedantic-errors
&amp;时使用了g++
clang++
我使用了/W4
&amp;使用VC ++编译器时的/Za
选项。观看现场演示here&amp; here。那么,我想知道模板类型参数T将如何推导出来?如果我从程序中删除const
,那么它也会在g++
上编译正常。如果我使用const T&
那么它在所有3个编译器上编译都很好。那么,在这些情况下,如何确切地推断出类型?
更新
此程序也无法在英特尔C ++编译器上进行编译。查看实时演示here。那么,这是g++
&amp;英特尔C ++或Clang++
&amp;中的错误VC ++?
答案 0 :(得分:9)
这基本上是CWG issue 1584:
目前尚不清楚以下是否格式良好:
void foo(){} template<class T> void deduce(const T*) { } int main() { deduce(foo); }
实施方案对此示例的处理方式各不相同。
目前仍处于活跃状态。它真的不可能说哪个编译器是正确的。虽然从2015年的说明中可以看出,CWG目前的共识是应该拒绝这一点。
为了给出更多的上下文,我们必须记住,具有cv-qualifier-seq的函数类型具有特殊含义(想想成员函数),并且不仅仅是指定可能不被修改的类型的类型。此外,你甚至不能以一种偷偷摸摸的方式添加cv资格,正如[dcl.fct]/7所示:
cv-qualifier-seq在函数声明符中的效果不是 与在函数类型之上添加cv-qualification相同。在里面 后一种情况,cv限定符被忽略。 [注意:一种功能类型 具有cv-qualifier-seq的不是cv限定类型;没有 cv限定的函数类型。 - 尾注] [例子:
typedef void F(); struct S { const F f; // OK: equivalent to: void f(); };
- 结束示例]
语言中没有办法形成const限定的函数类型。然而,我们需要的推论是将const T
推导为void()
。前者是一个const限定类型,它也必须是一个函数类型。但那是一种不存在的类型!那怎么能推断出来呢?!
另一方面,如果您使用的是引用而不是指针,则标准中有一些机器可以推导出它。
所以不清楚如何解决这个问题。一方面,今天的措辞本身并不允许,但另一方面,它的机制已经到位以供参考。因此,有些实现会继续执行并为指针执行相同操作。