Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I derive and add new arguments to the base version of the constructor?

I'm trying to extend a base class with some data members and hence need some additional constructor arguments in addition to the constructor arguments that my base class needs. I want to forward the first constructor arguments to the base class. Here's what I tried:

#include <string>
#include <utility>

struct X
{
    X( int i_ ) : i(i_) {}
    int i;
};

struct Y : X
{
    template <typename ...Ts>        // note: candidate constructor not viable: 
    Y( Ts&&...args, std::string s_ ) // requires single argument 's_', but 2 arguments 
//  ^                                // were provided
    : X( std::forward<Ts>(args)... )
    , s( std::move(s_) )
    {}

    std::string s;
};

int main()
{
    Y y( 1, "" ); // error: no matching constructor for initialization of 'Y'
//    ^  ~~~~~
}

However, the compiler (clang 3.8, C++14 mode) spits the following error messages at me (the main messages are also in the above source code for reading convenience):

main.cpp:23:7: error: no matching constructor for initialization of 'Y'
    Y y( 1, "" );
      ^  ~~~~~
main.cpp:13:5: note: candidate constructor not viable: requires single argument 's_', but 2 arguments were provided
    Y( Ts&&...args, std::string s_ )
    ^
main.cpp:10:8: note: candidate constructor (the implicit move constructor) not viable: requires 1 argument, but 2 were provided
struct Y : X
       ^
main.cpp:10:8: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 2 were provided
1 error generated.

Why is clang trying to tell me, that my templated constructor has only one arguments, even though the number of arguments is variadic? How can I solve this?

like image 254
Ralph Tandetzky Avatar asked Jun 22 '16 17:06

Ralph Tandetzky


People also ask

How do you pass arguments to the base class constructor?

To pass arguments to a constructor in a base class, use an expanded form of the derived class' constructor declaration, which passes arguments along to one or more base class constructors. Here, base1 through baseN are the names of the base classes inherited by the derived class.

Can a constructor be derived from base class?

To call the parameterized constructor of base class when derived class's parameterized constructor is called, you have to explicitly specify the base class's parameterized constructor in derived class as shown in below program: C++

When both derived and base class contain constructors what will happen?

However, if a base class contains a constructor with one or more arguments, then it is mandatory for the derived class to have a constructor and pass the arguments to the base class constructor. Remember, while applying inheritance, we usually create objects using derived class.

How do you initialize a base class constructor from a derived class?

We have to call constructor from another constructor. It is also known as constructor chaining. When we have to call same class constructor from another constructor then we use this keyword. In addition, when we have to call base class constructor from derived class then we use base keyword.


1 Answers

Here is a possible solution:

#include <string>
#include <utility>
#include<functional>
#include<tuple>
#include<iostream>

struct X
{
    X( int i_ ) : i(i_) {}
    int i;
};

struct Y : X
{
    template<std::size_t... I, typename... A>
    Y(std::integer_sequence<std::size_t, I...>, std::tuple<A...> &&a)
        : X( std::get<I>(a)... ),
          s(std::move(std::get<sizeof...(I)>(a)))
    { }

    template <typename ...Ts>
    Y( Ts&&...args )
        : Y{std::make_index_sequence<sizeof...(Ts)-1>(),
          std::forward_as_tuple(std::forward<Ts>(args)...)}
    { }

    std::string s;
};

int main()
{
    Y y( 1, "foo" );
    std::cout << y.s << std::endl;
}
like image 76
skypjack Avatar answered Sep 21 '22 06:09

skypjack