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 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]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With