Search code examples
c++templatesinheritancetypedefusing

Unable to import of typedefs from template base class


This question is not duplicate but follow up of Propagating 'typedef' from based to derived class for 'template'

As a solution to inheriting of the typedefs, it was suggested to use using to import them to derived class, whereas simple using typename Base::typedefed_typeis supposed to suffice.

The following code is mostly taken from Roman Kruglov's answer:

#include <vector>
template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A::Vec_t;
    // .........

private:
    Vec_t v;
};

int main()
{
B<int> bb;
}

However it fails to compile, because compilers badly want template arguments of A.

Intel compiler error message:

    1>C:\Work\EDPS\test_eigen\test_eigen.cpp(27): error : argument list for class template "A" is missing
1>      using typename A::Vec_t;
1>                     ^
1>          detected during instantiation of class "B<T> [with T=int]" at line 34
1>
1>C:\Work\EDPS\test_eigen\test_eigen.cpp(31): error : identifier "Vec_t" is undefined
1>      Vec_t v;
1>      ^
1>          detected during instantiation of class "B<T> [with T=int]" at line 34
1>

MVC Error message:

 c:\work\edps\test_eigen\test_eigen.cpp(27): error C2955: 'A': use of class template requires template argument list
1>c:\work\edps\test_eigen\test_eigen.cpp(17): note: see declaration of 'A'
1>c:\work\edps\test_eigen\test_eigen.cpp(32): note: see reference to class template instantiation 'B<T>' being compiled
1>c:\work\edps\test_eigen\test_eigen.cpp(27): error C3210: 'A': a member using-declaration can only be applied to a base class member
1>c:\work\edps\test_eigen\test_eigen.cpp(32): warning C4624: 'B<int>': destructor was implicitly defined as deleted

So what's wrong? Am I missing something? Or are perhaps the comments and answers there wrong??


Solution

  • I think the confusion arises from the way A is used as a base class. If a class template derives from a class template with a template argument, you have to fully qualify the base class name. But if a class derives from a class template specialization, you can use the base class name without a template argument list.

    template<typename T>
    struct A {
        using t = T;
    };
    
    template<typename T>
    struct B : A<T> {
        using typename A<T>::t; // Full qualification needed -> mandatory argument list
    };
    
    struct C : A<int> {
        using typename A::t; // Injected class name -> optional argument list
    };
    

    Live on Coliru

    Also, note that t is available in C directly, without any using declaration or typedef. I may still be useful, for example if C inherits from A<int> privately, but you want t to be available publicly in C (in the example, C inherits publicly by default because it is a struct).