为什么不能在没有显式 & on 函数名的情况下将函数指针与模板函数进行比较?

Why can't one compare a function pointer to a template function without explicit & on function name?

考虑以下代码:

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++ 是正确的,那么为什么普通函数与模板函数在显式寻址运算符的需要方面存在如此不对称?

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

A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. — end note ] The target can be:

(1.1) — an object or reference being initialized (8.5, 8.5.3, 8.5.4),

(1.2) — the left side of an assignment (5.18),

(1.3) — a parameter of a function (5.2.2),

(1.4) — a parameter of a user-defined operator (13.5),

(1.5) — the return value of a function, operator function, or conversion (6.6.3),

(1.6) — an explicit type conversion (5.2.3, 5.2.9, 5.4), or

(1.7) — a non-type template-parameter (14.3.2).

The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed. [ Note: Any redundant set of parentheses surrounding the overloaded function name is ignored (5.1). — end note ]

你看到从 (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 错误。