考虑以下程序:
#include <iostream>
template <typename T>
void foo(const T* x) {
x();
}
void bar() { std::cout<<"bar() is called\n"; }
int main() {
foo(bar);
}
它在 clang++
和 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);
^
我在使用 g++
和 clang++
时使用了 -pedantic-errors
并且我使用了 /W4
& /Za
使用 VC++ 编译器时的选项。查看现场演示 here & here .所以,我想知道这里如何推导模板类型参数 T ?如果我从程序中删除 const
那么它也可以在 g++
上正常编译。如果我使用 const T&
那么它在所有 3 个编译器上都能正常编译。那么,在这些情况下,这里将如何推导出类型?
更新:
此程序在英特尔 C++ 编译器上的编译也失败。查看现场演示 here .那么,这是 g++
和 Intel C++ 中的错误还是 Clang++
和 VC++ 中的错误?
最佳答案
这本质上是 CWG issue 1584 :
It is not clear whether the following is well-formed or not:
void foo(){} template<class T> void deduce(const T*) { } int main() { deduce(foo); }
Implementations vary in their treatment of this example.
目前仍然有效。真的不可能说哪个编译器是正确的。尽管如 2015 年的说明所示,CWG 目前的共识是应拒绝该提议。
为了提供更多上下文,我们必须记住带有 cv-qualifier-seq 的函数类型具有特殊含义(想想成员函数),而不仅仅是一种类型,它指定了一些不可修改的东西。此外,您甚至不能以某种偷偷摸摸的方式添加 cv 资格,如 [dcl.fct]/7说明:
The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top of the function type. In the latter case, the cv-qualifiers are ignored. [ Note: A function type that has a cv-qualifier-seq is not a cv-qualified type; there are no cv-qualified function types. — end note ][ Example:
typedef void F(); struct S { const F f; // OK: equivalent to: void f(); };
— end example ]
该语言无法形成 const 限定函数类型。然而,我们需要的推导是将 const T
推导为 void()
。前者是一个const限定类型,而且还必须是一个函数类型。但那是不可能存在的类型!那么怎么推导呢?!
另一方面,如果您使用的是引用而不是指针,则标准中有机制可以推断出它。
所以目前还不清楚应该如何解决这个问题。一方面,今天的措辞本身不允许它,但另一方面,它的机制已经到位以供引用。因此,一些实现会继续对指针执行相同的操作。
关于c++ - 函数指针的模板参数推导(g++ & ICC vs Clang++ & VC++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49295709/