During resolution of an overload of a templated member function of a base class, I observed a different behaviour between g++ (5.2.1-23) and clang (3.8.0), with -std=c++14
.
#include <iostream>
#include <type_traits>
struct Base
{
template <typename T>
auto a(T t) -> void {
std::cout<< "False\n";
}
};
template <bool Bool>
struct Derived : public Base
{
using Base::a;
template <typename T, bool B = Bool>
auto a(T t) -> std::enable_if_t<B, void>
{
std::cout<< "True\n";
}
};
int main()
{
Derived<true> d;
d.a(1); // fails with g++, prints "true" with clang
Derived<false> d2;
d2.a(1); // fails with clang++, prints "false" with g++
}
The call to Derived<true>::a
fails with g++ with the following message:
test.cc: In function ‘int main()’:
test.cc:28:8: error: call of overloaded ‘a(int)’ is ambiguous
d.a(1);
^
test.cc:18:8: note: candidate: std::enable_if_t<B, void> Derived<Bool>::a(T) [with T = int; bool B = true; bool Bool = true; std::enable_if_t<B, void> = void]
auto a(T t) -> std::enable_if_t<B, void>
^
test.cc:7:8: note: candidate: void Base::a(T) [with T = int]
auto a(T t) -> void {
^
and the call to Derived<false>::a
fails with clang++ with the following message:
test.cc:32:6: error: no matching member function for call to 'a'
d2.a(1);
~~~^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with T = int, B = false]
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
My guess is that they interpret differently the using Base::a;
, and that it isn't considered in clang, whereas it's (maybe too much) considered in g++. What I thought would happen is that if Derived
has true
as parameter, then the call of a()
is dispatched to Derived
's implementation, whereas if the parameter is false
, the call is dispatched to Base::a
.
Are they both wrong? Who is right? Who should I submit a bug report to? Can somebody explain what is going on?
Thanks
From 3.3.10/p3 Name hiding [basic.scope.hiding]:
Also 7.3.3/p15 The using declaration [namespace.udecl]:
This is resolved during member name look-up. Thus, it's before template argument deduction. Consequently, as correctly TC mentioned in the comments Base template function is hidden no matter of SFINAE verdict.
Therefore CLANG is correct and GCC is wrong.