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

标签 c++ constants language-lawyer function-pointers 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);
}

它在 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/

相关文章:

c++ - unique_ptr<T,Deleter> 构造函数要求 Deleter 不抛出异常

c++ - 使用 SSE 内在函数复制少量数据的问题

c++ - 在插入符号下获取单词 - C++、wxWidgets

c++ - 如何使用 Qt 在 Linux 中读取文件设备?

c - NCURSES printw 正确输出 RETURN 和 SPACE 的键码

C++ 我应该用什么代替#define

c++ - 对于调用结果的复制初始化顺序,它是否被认为是 GCC 和 Clang 的错误?

c++ - 返回值的复制构造函数何时发生

c++ - 将指针数组传递给函数

c - C 中的静态、定义和常量