Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ and clang++ different behaviour with pointer to variadic template functions

Another "who's right between g++ and clang++ ?" question for C++ standard gurus.

The code is the following

template <typename ...>
struct bar
 { };

template <typename ... Ts>
void foo (bar<Ts...> const &)
 { }

int main ()
 {
   foo<int>(bar<int, long>{});     // g++ and clang++ compile

   (*(&foo<int>))(bar<int, long>{});  // g++ and clang++ give error

   (&foo<int>)(bar<int, long>{});  // clang++ compiles; g++ gives error
 }

The template function foo() receive a variadic template parameter bar.

The first call

   foo<int>(bar<int, long>{});     // g++ and clang++ compile

works for both clang++ ang g++.

If I understand correctly, with foo<int> is explicated only the first template parameter and this doesn't complete the list of Ts... parameters. So the compiler look at the argument (a bar<int, long> object) and deduce the full list.

The second call is different

     (*(&foo<int>))(bar<int, long>{});  // g++ and clang++ give error

If I understand correctly, with (&foo<int>) we get the pointer to the instantiation of foo where Ts... is exactly int (not only the first type of the list but the whole list) and dereferencing it (*(&foo<int>)) and calling it with a wrong argument (a bar<int, long> object) we get (clang++ and g++) a compilation error.

So far, so good.

The problem arises with the third call

   (&foo<int>)(bar<int, long>{});  // clang++ compiles; g++ gives error

that I was convinced (maybe I was wrong) equivalent the second one (we fix all template types in Ts..., then we call the function with a wrong parameter) but g++ seems agree (and gives error) where clang++ disagree (and compile without problem).

The question, as usual, is: who's right ?

like image 365
max66 Avatar asked Feb 05 '18 21:02

max66


1 Answers

Let's examine a simpler case:

template <class A, class B>void foo(B) {};

int main()
{
    (&foo<char>)(1);
}

clang++ compiles this, while g++ fails with the following message:

error: address of overloaded function with no contextual type information

Same message is given for e.g. this program:

void moo(int) {};
void moo(int*){};

int main()
{
    &moo != nullptr;
}

Apparently, the intent is to refer to [over.over], which talks about taking the address of an overloaded function. This place in the standard specifies in what contexts an overloaded function name can be used (RHS of an assignment, an argument in a function call etc). However it says

An overloaded function name shall not be used without arguments in contexts other than those listed. (emphasis mine)

Now, is foo in (&foo<char>)(1) used without arguments? g++ seems to sink so. However it happily compiles

(&moo)(1);

from the second example. So we have at least some inconsistency here. The same rules govern taking an address of a function template and an overloaded set, so (&foo<char>)(1) and (&moo)(1) should be either both valid or both invalid. The standard itself seems to indicate that hey should both be valid:

The overloaded function name can be preceded by the & operator [...] [Note: Any redundant set of parentheses surrounding the overloaded function name is ignored (5.1). — end note]

like image 164
n. 1.8e9-where's-my-share m. Avatar answered Oct 31 '22 16:10

n. 1.8e9-where's-my-share m.