【问题标题】:Why can't one compare a function pointer to a template function without explicit & on function name?为什么不能将函数指针与没有显式 & 函数名称的模板函数进行比较?
【发布时间】:2017-07-19 11:01:02
【问题描述】:

考虑以下代码:

void func(int) {}
template<typename T> void templatedFunc(T) {}
int main()
{
    void (*p)(int) = func;

    bool test1 = p==func;
    //bool test2 = p==templatedFunc<int>; // compilation error
    bool test3 = p==&templatedFunc<int>; // but this works
}

如果您取消注释test2 行并尝试使用g++ 编译代码,您将收到以下错误:

test.cpp: In function ‘int main()’:
test.cpp:8:21: error: assuming cast to type ‘void (*)(int)’ from overloaded function [-fpermissive]
     bool test2 = p==templatedFunc<int>; // compilation error
                     ^~~~~~~~~~~~~~~~~~

我在 g++ 5.3.0 和 6.2.0 上得到了这个结果。同时用clang++ 3.6.0编译成功,没有警告。

根据此处的标准,哪个编译器是正确的 - g++,它会给出错误或 clang++,哪个没有?

如果 g++ 是正确的,那么为什么在需要显式地址运算符方面,普通函数与模板函数存在这种不对称?

【问题讨论】:

  • 我的常识告诉我,clang 在这种情况下是正确的,因为一个完全专用的函数模板(或者更确切地说是一个实例化)被认为是一个正常的函数,因此应该像这样运行。
  • 它是否允许您使用void (*p)(int) = templatedFunc&lt;int&gt;;,或者这是否也需要&amp;
  • 顺便说一句,惯用的方法是使用&amp;
  • @TripeHound 奇怪的是,g++ 在这种情况下没有抱怨。

标签: c++ templates function-pointers


【解决方案1】:

这是一个 gcc 错误,您处于极端情况,在 C++ 标准中,重载函数的地址§13.4 ([over.over]/1):

在某些上下文中使用不带参数的重载函数名称被解析为一个函数,一个 指向函数的指针或指向重载集中特定函数的成员函数的指针。一个函数 模板名称被认为是在这样的上下文中命名一组重载函数。选择的功能 是其类型与上下文中所需的目标类型的函数类型相同的类型。 [ 笔记: 也就是说,在匹配指向成员函数的指针时,忽略该函数所属的类 类型。 — 尾注] 目标可以是:

(1.1) — 正在初始化的对象或引用 (8.5, 8.5.3, 8.5.4),

(1.2) — 赋值的左侧 (5.18),

(1.3) — 函数 (5.2.2) 的参数,

(1.4) — 用户定义运算符 (13.5) 的参数,

(1.5) — 函数、运算符函数或转换的返回值 (6.6.3),

(1.6) — 显式类型转换(5.2.3、5.2.9、5.4),或

(1.7) — 非类型模板参数 (14.3.2)。

重载的函数名前面可以有 & 运算符。重载的函数名不应 在列出的上下文之外的上下文中不带参数使用。 [注:任何多余的括号集 忽略重载函数名称周围的 (5.1)。 ——尾注]

您是否看到从 (1.1) 到 (1.7) 的列表中缺少什么...内置运算符!

如果您声明 operator == 的重载,则两个 gcc 都不会抱怨比较,而且您不必显式专门化模板函数:

void func(int) {}
template<class T>
void templatedFunc(T) {}
struct s{};
bool operator==(s, void(*)(int)){return false;}
int main()
{
   void (*p)(int) = templatedFunc;

   bool test1 = p==func;
   bool test2 = s{} == templatedFunc<int>; // no error - no overload resolution
   bool test3 = s{} == templatedFunc; // no error - overload resolution
   bool test4 = p == templatedFunc<int>; // gcc error, but not an error -
                                         // no overload resolution
 //bool test5 = p == templatedFunc; // error - overload resolution not
                                 // performed for built-int operators

}

test2test3 使用 gcc 编译。 test4 不能在 gcc 上编译,但是没有重载决议,你明确地专门化了这个函数。它真的应该编译。 test5 没有按照标准中的说明进行编译。在这种情况下,gcc 会产生与test4 完全相同的错误消息。这肯定是一个 gcc 错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多