【问题标题】:template argument deduction for function pointer (g++ & ICC vs Clang++ & VC++ )函数指针的模板参数推导(g++ & ICC vs Clang++ & VC++)
【发布时间】:2018-03-15 09:30:23
【问题描述】:

考虑以下程序:

#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,在使用VC++ 编译器时我使用了/W4/Zaoption。查看现场演示 herehere。那么,我想知道模板类型参数 T 将如何推导出来?如果我从程序中删除const,那么它也可以在g++ 上正常编译。如果我使用const T&amp;,那么它在所有 3 个编译器上都可以正常编译。那么,在这些情况下,这里将如何准确推断类型?

更新:

该程序在英特尔 C++ 编译器上的编译也失败。见现场演示here。那么,这是 g++ 和英特尔 C++ 中的错误还是 Clang++ 和 VC++ 中的错误?

【问题讨论】:

  • 使用模板传递函数或谓词的通常方式是普通的“值”,例如template &lt;typename T&gt; void foo(T x) { x(); } 参见例如以the standard algorithm library 中的几乎所有功能为例。您能否详细说明您想使用const 指针的原因?

标签: c++ constants language-lawyer function-pointers template-argument-deduction


【解决方案1】:

这本质上是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-qualified 类型;没有 cv 限定的函数类型。 — 尾注 ][ 示例:

typedef void F();
struct S {
  const F f;        // OK: equivalent to: void f();
};

— 结束示例 ]

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

另一方面,如果您使用引用而不是指针,标准中有机制可以推断它。

所以目前还不清楚应该如何解决这个问题。一方面,今天的措辞本身不允许,但另一方面,它的机制已经到位,可供参考。所以一些实现会继续对指针做同样的事情。

【讨论】:

  • 看来根本问题是函数类型没有 cv 限定类型。不明白为什么...赞成。
  • @liliscent - 正如我所见,我试图解释它。
  • 你说如果你使用引用而不是指针,标准中有机制来推断它。您能否以简单的方式解释当我通过引用标准来使用参考时会发生什么。我的意思是在引用的情况下如何推断类型?
  • @Destructor - 恐怕提到有机器是我个人能做到的最简单的。有一堆特别的cases for references,最终最终允许它。寻找诸如 " P 不是引用类型"" P 是引用类型" 之类的东西
  • @Destructor 我认为当前的问题已经解决了,这个答案已经非常有用了。最好再问一个问题,这样也方便google搜索。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-15
  • 2016-12-16
  • 2016-12-30
  • 1970-01-01
  • 2021-05-23
  • 1970-01-01
相关资源
最近更新 更多