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?
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.
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++
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.
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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With