函数指针的模板参数推导(g ++&ICC vs Clang ++&VC++)

Des*_*tor 8 c++ const function-pointers language-lawyer template-argument-deduction

考虑以下计划:

#include <iostream>
template <typename T>
void foo(const T* x) {
    x();
}
void bar() { std::cout<<"bar() is called\n"; }
int main() {
    foo(bar);
}
Run Code Online (Sandbox Code Playgroud)

它编译罚款clang++&VC++g++给人以下编译器错误(见现场演示这里)

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);
         ^
Run Code Online (Sandbox Code Playgroud)

-pedantic-errors在使用g++&时使用了,clang++并且在使用VC++编译器时我使用了/W4&/Zaoption.在这里这里观看现场演示.那么,我想知道模板类型参数T将如何推导出来?如果我const从程序中删除它然后编译g++也很好.如果我使用const T&它然后它编译所有3编译器罚款.那么,在这些情况下,如何确切地推断出类型?

更新:

此程序也无法在英特尔C++编译器上进行编译.在这里查看现场演示.那么,这是g++英特尔C++中的错误还是Clang++VC++中的错误?

Sto*_*ica 9

这基本上是CWG问题1584:

目前尚不清楚以下是否形成良好:

void foo(){}
template<class T>   void deduce(const T*) { }

int main() {
  deduce(foo);   
}
Run Code Online (Sandbox Code Playgroud)

实施方案对这个例子的处理方式各不相同.

目前仍处于活跃状态.真的不可能说哪个编译器是正确的.虽然从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();
};
Run Code Online (Sandbox Code Playgroud)

- 结束例子]

语言中没有办法形成const限定函数类型.然而,我们需要的推论是const T推导出来的void().前者 const限定类型,它也必须是函数类型.但那是一种不存在的类型!那怎么能推断出来?!

另一方面,如果您使用引用而不是指针,则标准中有机器可以推导出它.

所以不清楚如何解决这个问题.一方面,今天的措辞本身并不允许,但另一方面,它的机制已经到位以供参考.所以一些实现继续进行,并为指针做同样的事情.