Reputation: 60391
Consider the following code, in C++11, tested with g++-6
, g++-7
, clang++-3.8
and clang++-4.0
// Preamble
#include <iostream>
// Base 0
template <class T, template <class, T...> class Derived>
struct base0 {
void operator=(int) {std::cout << "base0::operator=\n";}
};
// Base 1
template <class T, int N, template <class, T...> class Derived>
struct base1 {
void operator=(int) {std::cout << "base1::operator=\n";}
};
// Derived 0
template <class T, int N>
struct derived0: base0<int, derived0> {
using base0::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = SUCCESS
using base0<int, derived0>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Derived 1
template <class T, int N>
struct derived1: base1<int, N, derived1> {
using base1::operator=; // g++6/7 = ERROR, clang++-3.8/4.0 = ERROR
using base1<int, N, derived1>::operator=; // g++6/7 = SUCCESS, clang++-3.8/4.0 = ERROR
};
// Main
int main()
{
derived0<int, 3> object0;
derived1<int, 3> object1;
object0 = 42;
object1 = 42;
return 0;
}
g++ and clang++ do not produce errors with the same version of the using base::operator=
. Which one of them is right, and what does the C++ standard say?
Upvotes: 1
Views: 125
Reputation: 137345
This is Clang not implementing DR1004 and hence not allowing the injected-class-name of derived0/1
to be used as a template-name.
GCC's handling of your code appears to be correct in all cases. The difference between 0 and 1 is due to the base being nondependent in 0 but dependent in 1. In the former case name lookup for base0
finds its injected-class-name which can be validly used as a type name. In the latter case, name lookup skips the dependent base and finds the ::base1
template instead.
Upvotes: 2