请注意,首选术语(即未来版本的规范中的术语)现在是转发参考.
正如您所说,转发引用仅适用于函数模板中的类型推导。在你的情况下,当你说T&&
, T
is int
。不可能是int&
因为它已在您的中明确说明Bar
实例化。因此,引用崩溃规则不会发生,因此您无法进行完美的转发。
如果你想在这样的成员函数中进行完美的转发,你需要有一个成员函数模板:
template <typename U>
void foo(U&& arg)
{
std::forward<U>(arg); //actually do something here
}
如果你绝对需要U
具有相同的非限定类型T
,你可以做一个static_assert
:
template <typename U>
void foo(U&& arg)
{
static_assert(std::is_same<std::decay_t<U>,std::decay_t<T>>::value,
"U must be the same as T");
std::forward<U>(arg); //actually do something here
}
std::decay
对你来说可能有点太激进了,因为它将把数组类型衰减为指针。如果这不是您想要的,您可以编写自己的简单特征:
template <typename T>
using remove_cv_ref = std::remove_cv_t<std::remove_reference_t<T>>;
template <typename T, typename U>
using is_equiv = std::is_same<remove_cv_ref<T>, remove_cv_ref<U>>;
如果您需要可变版本,我们可以编写一个are_equiv
特征。首先,我们需要一个特征来检查包中的所有特征是否都为真。我将使用bool_pack
method:
namespace detail
{
template<bool...> struct bool_pack;
template<bool... bs>
using all_true = std::is_same<bool_pack<bs..., true>, bool_pack<true, bs...>>;
}
template <typename... Ts>
using all_true = detail::all_true<Ts::value...>;
然后我们需要一些东西来检查每对类型是否Ts...
and Us...
满足is_equiv
。我们不能将两个参数包作为模板参数,因此我将使用 std::tuple 来分隔它们(您可以使用哨兵节点,或者如果您愿意,可以将包中途拆分):
template <typename TTuple, typename UTuple>
struct are_equiv;
template <typename... Ts, typename... Us>
struct are_equiv <std::tuple<Ts...>, std::tuple<Us...>> : all_true<is_equiv<Ts,Us>...>
{};
然后我们可以像这样使用它:
static_assert(are_equiv<std::tuple<Ts...>,std::tuple<Us...>>::value,
"Us must be equivalent to Ts");