简体   繁体   中英

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 ?

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 eg 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 ]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM