Reputation: 23610
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?
Upvotes: 5
Views: 174
Reputation: 50550
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;
}
Upvotes: 3
Reputation: 2237
You have to move varargs to the end of arguments list.
#include <string>
#include <utility>
struct X
{
X( int i_ ) : i(i_) {}
int i;
};
struct Y : X
{
template <typename ...Ts>
Y( std::string s_, Ts&&...args ) // <==== like this
: X( std::forward<Ts>(args)... )
, s( std::move(s_) )
{}
std::string s;
};
int main()
{
Y y( "", 1 );
}
Upvotes: 3