我想用一个实现相同功能的可变参数模板替换这些宏。
#define SHFT2( a, b, c ) do { (a) = (b); (b) = (c); } while(0)
#define SHFT3( a, b, c, d ) do { (a) = (b); (b) = (c); (c) = (d); } while(0)
#define SHFT4( a, b, c, d, e ) do { (a) = (b); (b) = (c); (c) = (d); (d) = (e); } while(0)
我有一个适用于左值的解决方案
template<typename T, typename... Ts>
T first(T t, Ts... ts)
{
return t;
}
template<typename T>
void shift(T t)
{
// do nothing
}
template<typename T, typename... Ts>
void shift(T& t, Ts&... ts)
{
t = first(ts...);
shift(ts...);
}
例如,这可行
int w = 1;
int x = 2;
int y = 3;
int z = 4;
shift(w, x, y, z);
printf("%d %d %d %d\n", w, x, y, z); // 2 3 4 4
但我希望能够在最后转入右值
shift(w, x, y, z, 5);
printf("%d %d %d %d\n", w, x, y, z); // expect 2 3 4 5
我收到此错误
test.cpp:31:2: error: no matching function for call to 'shift'
shift(w, x, y, z, 5);
^~~~~
test.cpp:16:6: note: candidate function [with T = int, Ts = <int, int, int, int>] not viable: expects an l-value for 5th
argument
void shift(T& t, Ts&... ts)
^
test.cpp:10:6: note: candidate function template not viable: requires single argument 't', but 5 arguments were provided
void shift(T t)
因为您无法引用右值。
如何在这两种情况下都能完成这项工作?
答案 0 :(得分:1)
您可以使用转发引用参数来接受左值和右值,并使用std::forward
来“转发”原始参数的值类别,即将参数转换为匹配值类别。
template <typename T>
void shift(T&& t) {
// do nothing
}
template<typename T1, typename T2, typename... Ts>
void shift(T1&& t1, T2&& t2, Ts&&... ts) {
std::forward<T1>(t1) = std::forward<T2>(t2);
shift(std::forward<T2>(t2), std::forward<Ts>(ts)...);
}
这里,std::forward<T1>(t1)
确保t1
如果参数是左值,将被分配为左值,如果参数是右值,则确定为右值。例如,shift(42, x)
将无法编译,因为无法将int
类型的右值分配给。{/ p>
std::forward<T2>(t2)
确保如果t2
的参数是左值,它将被复制,而如果它是右值,则会在可能的情况下移动它。
std::forward<T2>(t2)
和std::forward<Ts>(ts)...
将值类别信息传递给递归调用。
答案 1 :(得分:1)
你想要像
这样的东西#include <utility>
// abort
template <class T> void shift(T&&) { }
// assign to lvalue
template<class T1, class T2, class... Ts>
void shift(T1& t1, T2&& t2, Ts&&... ts)
{
t1 = std::forward<T2>(t2);
shift(std::forward<T2>(t2), std::forward<Ts>(ts)...);
}
期望所有参数,但最后一个是左值,其中最后一个也可能是左值。
shift(T&&)
。t1
,确保lvalues已在任何插槽中传递,但最后一个插槽。即。 shift(w, x, y, z, 5);
已编译,但shift(w, x, y, 5, z);
或shift(w, x, y, 5, 5);
没有。
答案 2 :(得分:1)
因为您无法引用右值。
您将参数声明为左值引用,只需将它们更改为forwarding references,根据传入参数的值类别,将其作为左值引用和右值引用。 e.g。
template<typename T, typename... Ts>
T&& first(T&& t, Ts&&... ts)
{
return std::forward<T>(t);
}
template<typename T>
void shift(T&& t)
{
// do nothing
}
template<typename T, typename... Ts>
void shift(T&& t, Ts&&... ts)
{
t = first(std::forward<Ts>(ts)...);
shift(std::forward<Ts>(ts)...);
}