In my C++11 code, I have a variadic struct and a function that should use perfect-forwarding for the struct's variadic types such as this:
template <typename... T>
struct S
{
void X(T&&... args)
{
Do(std::forward<T>(args)...);
}
};
Just assume that Do
is a free-standing variadic function. Given a type struct V { int x, y; };
I want to call S::X
like so:
S<V> s;
V v = { 1, 2 };
s.X(V()); // Compiles
s.X(v); // Does not compile
The last line produces the following error in Visual Studio 2013 and Visual Studio 2013 with the November 2013 CTP of the C++ compiler:
error C2664: 'void S<V>::X(V &&)' : cannot convert argument 1 from 'V' to 'V &&'
You cannot bind an lvalue to an rvalue reference
I tried mingw 4.8.1 and got a similar error, so it doesn't seem to be a compiler or C++11-support problem:
Source.cpp:51:7: error: cannot bind 'V' lvalue to 'V&&'
s.X(v); // error C2664: 'void S<V>::X(V &&)' : cannot convert argument 1 from 'V' to 'V &&'
^
Source.cpp:17:7: error: initializing argument 1 of 'void S<T>::X(T&& ...) [with T = {V}]'
void X(T&&... args)
^
I was surprised to find out that a call to s.X(v)
wouldn't work, as that is what universal references and perfect-forwarding are all about, right? While trying to figure out what's going on, I first noticed that it does indeed work when X is a free-standing variadic function, and it also works if I change X to be 'doubly variadic', in a sense:
template <typename... T>
struct S
{
template <typename... T2>
void X(T2&&... args)
{
Do(std::forward<T2>(args)...);
}
};
Now, calling both s.X(v)
and s.X(V())
work as expected, however, the relationship between the T
and T2
variadic template arguments is now unclear. Reading this stackoverflow question, I get the impression that the original version of X is in fact not using perfect-forwarding and universal references at all; instead, when S
's template arguments are expanded by the compiler, the definition of S::X
is also expanded, hence the function's prototype is actually void S::X(V&& v)
, in which case the error message makes perfect sense.
Can anyone confirm this behavior? Is there a way to have a true perfect-forwarding/universal reference function within a variadic struct without repeating the variadic arguments? If my suspicion is indeed correct, is that a defect of the current C++ standard?