This seems to be another "who's doing it well?" question since gcc 6.0.0 and clang 3.7.0 behaves different.
Let's suppose we have a variable template which takes a const char *
as non template argument and is specialized for a given pointer:
constexpr char INSTANCE_NAME[]{"FOO"};
struct Struct{ void function() const { std::cout << __PRETTY_FUNCTION__; } };
std::ostream &operator <<(std::ostream &o, const Struct &) { return o << INSTANCE_NAME; }
template <const char *> char Value[]{"UNKNOWN"};
// spezialization when the pointer is INSTANCE_NAME
template < > Struct Value<INSTANCE_NAME>{};
Note that the template variable have different types depending on the specialization. Ten we have two template functions, each of one takes a const char *
as non template argument and forwards it to the variable template:
template <const char *NAME> void print()
{
std::cout << Value<NAME> << '\n';
}
template <const char *NAME> void call_function()
{
Value<NAME>.function();
}
Then, calling this functions results in different behaviours:
int main()
{
print<INSTANCE_NAME>();
call_function<INSTANCE_NAME>();
return 0;
}
clang 3.7.0 prints FOO
and void Struct::function() const
(as I was expecting) while gcc 6.0.0 fails to compile with the error below:
request for member 'function' in 'Value', which is of non-class type 'char [8]'
I'm almost sure that gcc failed to forward the template non-type argument NAME
to the variable template Value
in the function call_function
and for this reason it selects the unspecialized variable template which is the one with 'char [8]'
type...
It is acting like it is copying the template argument. This only happens when calling a member function of the object, if we comment the body of call_function
, the output is FOO
not UNKNOWN
, so in the print
function the forwarding is working even in gcc.
So
- What's the correct behaviour? (mi bet is for clang)
- How can I open a bug ticket for the compiler who's doing it wrong?
There is a reasonable consensus that variable template specializations are permitted to alter the type of the variable template: C++1y/C++14: Variable Template Specialization?
The behavior of gcc is particularly interesting if the default type of
Value
is changed to a type with afunction
method:The bug appears to be that where the non-specialized variable template has a type that is not dependent on the variable template template parameters, gcc assumes within template methods that use that variable template that the variable template always has that type.
The workaround, as usual, is to unconditionally forward the variable template to a class template with specialization(s) of the class template, and with the necessary fiddling for ODR compliance.
Another (possibly easier) workaround is to make the non-specialized variable template type somehow dependent on the variable template template parameters; in your case this would work:
I can't find a corresponding issue in gcc bugzilla so you might want to enter a new one. Here's a minimal example: