带有右值参数调用的C++11模板函数
C++11 templated function with rvalue param call
在一些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((函数有关。
template<typename Args>
static void test2(Args&& args)
{ ... }
在上面的函数中,即使参数类型看起来像右值引用,它也可以绑定到右值和左值参数。这通常被称为通用引用。如果函数自变量是类型为U
的右值,则T
被推导为U
,而T&&
是U&&
,一个右值引用,这是直接的。然而,当函数参数是类型为U
的左值时,则T
将被推导为U&
,这意味着函数参数类型将是U& &&
,其经历引用折叠而变为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
,您将尝试将一个左值绑定到右值引用参数,但失败了。
基于对象的知识,在右值内引用对象,也引用右值。我决定以这个结尾(灵感来自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
对我来说足够短。
附言:如果有人对此有一些预防措施,我会很乐意听取他们的意见
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 为什么 -mmacosx-version-min=10.10 不阻止使用标记为从 10.11 开始的函数?
- C++11:模板方法的模板函数调用无法编译?
- 为什么即使调用了析构函数,C++11 中的分离线程也可以执行
- MacOS 上的 Xcode 11 项目不在一个函数中使用 sin 和 cos:未定义的符号"___sincosf_stret"
- 在 C++11 函数中使用尾随返回类型的优点
- 当加入 C++11 函数的线程仍未终止时,是否可以返回?
- 如何使用 c++11 函数回调声明多个模板参数
- 通用 C++11 函数包装器,用于基于任务的并行性
- 有没有办法<int><double>在使用 C++11 函数调用期间自动将"向量"提升为"向量"?
- 如何使C++11函数生效<>参数自动接受lambdas
- 如何将可变数量的不同类型的参数传递给 C++11 函数映射中的函数
- 看看c++11函数是如何实现的
- Eclipse Luna 无法解析 c++11 函数"stoi"
- 用可变的std::function的c++ 11函数签名
- 使用NSS调用pkcs#11函数
- 从现代C++11函数转换为原始函数指针
- c++ 11函数返回时会发生什么
- 带有auto关键字的c++ 11函数定义
- __func__ C++11 函数的局部预定义变量,无法编译