When I uncomment the line in main() below, Visual Studio 2015 won't compile (the code compiles otherwise).
#include <iostream>
#include <type_traits>
template <typename Output, std::size_t... Input> struct RemoveLastHelper;
template <template <std::size_t...> class Z, std::size_t... Accumulated, std::size_t First, std::size_t... Rest>
struct RemoveLastHelper<Z<Accumulated...>, First, Rest...> :
RemoveLastHelper<Z<Accumulated..., First>, Rest...> {};
template <template <std::size_t...> class Z, std::size_t... Accumulated, std::size_t Last>
struct RemoveLastHelper<Z<Accumulated...>, Last> {
using type = Z<Accumulated...>;
};
template <template <std::size_t...> class Z, std::size_t... Is>
using RemoveLast = RemoveLastHelper<Z<>, Is...>;
struct Base {
virtual ~Base() = default;
virtual void foo() const = 0;
};
template <std::size_t... Is> struct Derived;
template <std::size_t R>
struct Derived<R> : public Base {
virtual void foo() const override {}
};
// For example, Derived<R,D1,D2,D3> inherits from Derived<R,D1,D2>, which inherits from
// Derived<R,D1>, which inherits from Derived<R>, which inherits from Base (by the above).
template <std::size_t R, std::size_t... Is>
struct Derived<R, Is...> : public RemoveLast<Derived, R, Is...>::type {
virtual void foo() const override {RemoveLast<Derived, R, Is...>::type::foo();}
};
int main() {
// Derived<0,2,1> r; // This line won't compile.
}
It gives the errors:
'Derived<0,2>': invalid template argument for template parameter 'Z', expected a class template
'RemoveLast': left of '::' must be a class/struct/union
'type': is not a class or namespace name
So what is wrong here? GCC 5.1 compiles it but I wonder if that's just a fluke or not. Is the syntax virtual void foo() const override {RemoveLast<Derived, R, Is...>::type::foo();}
legal? If not, how do I achieve it (I merely want it to call its base class's foo()). If it is legal, how do I rewrite this so that Visual Studio will accept it (I need it working on Visual Studio)?
This is a simple fix. Replace Derived
with Derived::template Derived
.
template <std::size_t R, std::size_t... Is>
struct Derived<R, Is...> : public RemoveLast<Derived, R, Is...>::type {
virtual void foo() const override {RemoveLast<Derived::template Derived, R, Is...>::type::foo();}
};
::Derived
works too. This appears to be a bug that exists in both Clang and Visual Studio regarding injected class names.