在某些O类中,我有模板函数test2
:
struct A{int value;};
struct O{
A value;
template<typename Args>
static void test2(Args &&args){
std::cout << std::endl << "!!!" << std::is_rvalue_reference<decltype(args)>::value << std::endl;
}
};
然后,我想从另一个人那里调用这个函数:
template<typename Args>
void test(Args &&args){
using t = decltype(std::forward<Args>(args).value);
std::cout << std::is_rvalue_reference<decltype(args)>::value;
std::cout << std::is_rvalue_reference<decltype(std::forward<Args>(args).value)>::value;
std::cout << std::is_rvalue_reference<t>::value;
// All ok
O.test2(std::forward<Args>(args).value);
// Alvays rvalue, even if agrs is lvalue
O::template test2<t>(
std::forward<t>(
std::forward<Args>(args).value
)
);
// Nor work at all, cant cast A to A&&
O::template test2<t>(
std::forward<Args>(args).value
);
);
}
http://coliru.stacked-crooked.com/a/3bbf040904845a54
如果我只是在没有指定模板类型的情况下传递std::forward<Args>(args).value
,它会正确推断类型,但是如果我必须传递类型,我应该如何调用函数?
似乎我无法正确地手动推断出类型。
更新
我需要明确指定参数,因为我有这样的函数(伪代码):
//initially call wind from somewhere.
// Tuple defined in class and is std::tuple
template<class Callback, class ...Args>
void wind(Tuple&& tuple, Callback &&callback){
using elementT = decltype(std::get<index>(std::forward<Tuple>(tuple)));
///
/// !!! Problem here !!!
///
callback.template operator()<elementT, Args...>( std::get<index>(std::forward<Tuple>(tuple)) ); // std::get automatically return &/&&
// recursivly call wind until the end
wind<Callback, Args...>( std::forward<Tuple>(tuple), std::forward<Callback>(callback));
}
// callback looks like:
struct CallMe{
// Args provide type info. No function arguments here.
template<class Data, class ...Args>
void operator(Data &&data){
}
}
这个问题与调用wind和callback()函数有关。
答案 0 :(得分:5)
template<typename Args>
static void test2(Args&& args)
{ ... }
在上面的函数中,即使参数类型看起来像一个右值引用,它也可以绑定到rvalue和lvalue参数。这通俗地称为 通用引用 。如果函数参数是U
类型的右值,那么T
推导为U
,而T&&
是U&&
,这是一个右值参考,很简单。但是,当函数参数是U
类型的左值时,T
将推导为U&
,这意味着函数参数类型将为U& &&
,其经历< strong> 引用折叠 成为U&
。但是,要应用这些特殊规则,必须推断 类型 。
O::test2(std::forward<Args>(args).value); // changed O.test2 to O::test2
在这种情况下,模板参数类型是从函数参数推导出来的。参数本身是左值,因此函数参数args
的类型也是左值。
O::template test2<t>(
std::forward<t>(
std::forward<Args>(args).value
)
);
这里的区别在于您已明确指定test2
的模板参数类型。没有进行推论,在这种情况下,函数参数是一个简单的右值引用。它只能绑定到右值,并且由于外部std::forward<t>
强制转换(此处为t = A
)而提供此右值。它与static_cast<A&&>(value)
具有相同的效果。
O::template test2<t>(
std::forward<Args>(args).value
);
最后一个案例应该解释为什么这不起作用。如上所述,在这种情况下,test2
只能绑定到右值,如果没有上面的第二个std::forward
,您就会尝试将左值绑定到一个失败的右值引用参数。
答案 1 :(得分:0)
Based on knowledge that objects, inside rvalue referenced object, also rvalue referenced。 我决定最终得到这个(受https://stackoverflow.com/a/24083200/1559666启发):
template<class T, class FieldT>
using addRefU = typename std::conditional<
std::is_rvalue_reference<T>::value,
typename std::add_rvalue_reference< FieldT >::type,
typename std::conditional<
std::is_rvalue_reference<FieldT>::value,
typename std::add_rvalue_reference< FieldT >::type,
typename std::add_lvalue_reference< FieldT >::type
>::type
>::type;
T T::value(FieldT) resolve
------------------------------------------------------------
rvalue lvalue rvalue
rvalue rvalue rvalue
lvalue rvalue rvalue
lvalue lvalue lvalue
using t = addRefU<decltype(args), decltype(args.value)>;
O::template test2<t>(
static_cast<t>(args.value)
);
http://coliru.stacked-crooked.com/a/40d10f5a2f45c288
对我来说足够短。
P.S。如果有人对此有一些预防措施,我很乐意听取他们的意见。