Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must I create a type alias when using a variadic constructor function?

I have a templated base class that takes an N amount of types:

template <typename... Ts>
class Base{};

When using protected inheritance on that base class,

template <typename... Ts>
class Derived : protected Base<Ts...>{
   //like so...
};

I would like to additionally include the public constructors of the base class:

template <typename... Ts>
class Derived : protected Base<Ts...>{

   //create an alias
   using Parent = Base<Ts...>;

   //get all constructors as well
   using Parent::Parent; 
};

This works.
However, why must I include the Parent alias?

Is doesn't seem as though I can get the constructors without it. The following attempt does not work:

template <typename... Ts>
class Derived : protected Base<Ts...>{

   //get all constructors as well
   using Base<Ts...>::Base<Ts...>; 
};

error:

clang++ -std=c++1z -o main v.cpp
error: expected ';' after using declaration
       using Base<Ts...>::Base<Ts...>; 
                              ^
                              ;
1 error generated.

I can cut off the template part, and it compiles, but this does not appear to be correct:

template <typename... Ts>
class Derived : protected Base<Ts...>{

   //get all constructors as well
   using Base<Ts...>::Base; 
};

The reason I don't think it is correct is because it does not appear to work on vector.
does not compile:

template <typename... Ts>
class Derived : protected std::vector<Ts...>{

   //get all constructors as well
   using std::vector<Ts...>::std::vector; 
};

However, using an alias does work.
compiles:

template <typename... Ts>
class Derived : protected std::vector<Ts...>{

   //create an alias
   using Parent = std::vector<Ts...>;

   //get all constructors as well
   using Parent::Parent; 
};

Question:
Do I have to use an alias to get the same functionally, or is there a way to inline this without creating a new name for the base type?

like image 338
Trevor Hickey Avatar asked Mar 16 '23 14:03

Trevor Hickey


2 Answers

You don't need a type alias. The problem is that the constuctor of Base<Ts...> is not called Base<Ts...>. It's called Base.

This works:

template<class...Ts>
struct Base {

};

template<class...Ts>
struct Derived : Base<Ts...>
{
    using Base<Ts...>::Base;
};

In addition, the name of std::vector<...>'s constructor is not std::vector, it is vector

This also works:

template<class...Ts>
struct Derived : std::vector<Ts...>
{
    using std::vector<Ts...>::vector;
};

However, don't derive from std:: containers! Encapsulate them.

like image 91
Richard Hodges Avatar answered Mar 18 '23 03:03

Richard Hodges


In your example Base does not have a template constructor so using Base<Ts...>::Base<Ts...>; is trying to find a constructor that does not exist.

Imagine I had a class like yours

class Base{
    public:
        Base(){}

        template<typename ... Ts>
        Base(){}
};

Which constructor would using Base<Ts...>::Base<Ts...> choose?

The reason that using Parent = Base<Ts...> works is because when you write using Parent::Parent you are trying to find a constructor of Parent that is not templated. It expands to using Base<Ts...>::Base;.

like image 32
RamblingMad Avatar answered Mar 18 '23 03:03

RamblingMad