Reputation: 9240
Why does the following not compile:
struct a
{
int i;
};
template <typename T>
class b
{
public:
T mItem;
template <typename... Arguments>
b(Arguments&&... args) : mItem(std::forward<Arguments>(args)...)
{
}
};
int _tmain(int argc, _TCHAR* argv[])
{
b<a>(1);
return 0;
}
error C2664: 'a::a(const a &)' : cannot convert argument 1 from 'int' to 'const a &'
But simply adding an extra argument like this make it compile:
struct a
{
int i;
};
template <typename T>
class b
{
public:
T mItem;
template <typename... Arguments>
// just random extra argument
b(int, Arguments&&... args) : mItem(std::forward<Arguments>(args)...)
{
}
};
int _tmain(int argc, _TCHAR* argv[])
{
b<a>(1);
return 0;
}
Is there a cleaner way than simply adding an extra (useless) argument to b's constructor?
Upvotes: 0
Views: 164
Reputation: 65630
You are trying to rely on aggregate-initialization, but you need to use braces rather than parentheses to use it:
template <typename... Arguments>
b(Arguments&&... args) : mItem{std::forward<Arguments>(args)...}
{
}
The braces mean that you are using list-initialization rather than value-/direct-initialization. The former resolves to aggregate-initialization when T
is an aggregate type, but the latter two do not. Yeah, C++ initialization rules are weird.
Upvotes: 5
Reputation: 62603
You are trying to initialize A with int. A does not know anything about int, there is no constructor in A which can do this. When you provide an extra int argument, you are just discarding it and than initialze A with empty argument list, calling default constructor.
Upvotes: -1
Reputation: 9997
In the first case you try to invoke
a(1)
which you have not.
In the second case, your 1
parameter is consumed by int
and the rest parameters (that is, none) goes to args
. Therefore, you invoke
a()
which is ok.
Note that in the latter case, the value of 1
which you passed to b<a>::b
is lost and is not forwarded to a::i
as you might have expected.
Upvotes: 1