Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Consider the following code:

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
}

If you uncomment the test2 line and try to compile the code with g++, you'll get the following error:

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
                     ^~~~~~~~~~~~~~~~~~

I get this result on g++ 5.3.0 and 6.2.0. At the same time, compilation with clang++ 3.6.0 succeeds without warnings.

Which compiler is correct according to the Standard here — g++, which gives an error or clang++, which doesn't?

And if g++ is right, then why is there such an asymmetry with normal functions vs templated functions regarding the need of explicit address-of operator?

like image 660
Ruslan Avatar asked Feb 28 '17 12:02

Ruslan


People also ask

Can we compare function pointer?

Pointers to objects or functions of the same type (after pointer conversions) can be compared for equality. Two pointers of the same type compare equal if and only if they are both null, both point to the same function, or both represent the same address (3.9. 2).

What is the difference between pointer and function?

1) Unlike normal pointers, a function pointer points to code, not data. Typically a function pointer stores the start of executable code. 2) Unlike normal pointers, we do not allocate de-allocate memory using function pointers. 3) A function's name can also be used to get functions' address.

What can not be done with function pointers?

2. What will we not do with function pointers? Explanation: As it is used to execute a block of code, So we will not allocate or deallocate memory.

When would you use a pointer to a function?

A pointer to a function points to the address of the executable code of the function. You can use pointers to call functions and to pass functions as arguments to other functions.


1 Answers

This is a gcc bug, and you are in a corner case, in the C++ standard, Address of overloaded function §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 ]

Do you see what is lacking in the list from (1.1) to (1.7)... built-in operators!

If you declare an overload of operator == both gcc will not complain with the comparison, more than that you do not have to explicitly specialize the template function:

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

}

test2 and test3 compiles with gcc. test4 does not compile on gcc, but there are no overload resolution, you explicitly specialized the function. It really should compile. test5 does not compile as stated in the standard. In this case gcc produces the exact same error message as for test4. This is surely a gcc bug.

like image 80
Oliv Avatar answered Sep 17 '22 12:09

Oliv