删除右值,保留左值引用(标准类型特征可用?)
Remove rvalueness, keep lvalue references (standard type trait available?)
我正在尝试编写一个 returns 形式为 std::tuple
的可变参数包子集的函数。理想情况下,该函数应该没有运行时开销(没有不必要的副本),并且它应该允许用户访问 lvalue
引用并修改它们。
值类型、lvalue
引用和 const lvalue
引用应保留。临时对象(rvalue
引用)应 "converted" 到值类型以避免创建无效引用(对临时对象的引用)。
期望结果示例:
int lr = 5;
const int& clr = lr;
auto t = make_subpack_tuple(lr, clr, 5);
static_assert(is_same
<
decltype(t),
std::tuple<int&, const int&, int>
>{}, "");
// Ok, modifies lr:
std::get<0>(t) = 10;
// Compile-time error, intended:
// std::get<1>(t) = 20;
// Ok, 5 was moved into the tuple:
std::get<2>(t) = 30;
不完整实施示例:
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple
<
some_type_trait<decltype(xs)>...
>
(
std::forward<decltype(xs)>(xs)...
);
}
我想做的事情有意义吗?
有没有标准的类型特征可以用来代替 some_type_trait
?还是我应该实施自己的解决方案?
适合您的解决方案是
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple<Ts...>(std::forward<Ts>(xs)...);
}
根据 template argument deduction rules, the parameter pack Ts...
will contain only cv-qualified types and lvalues. The information in this question 也可能有用。
我只想说,我 运行 在实现 Nick Athanasios's foldable Op<operation>
的高效版本时遇到了同样的不是真正的问题 ("I think I need to decay rvalue references and keep lvalue references untouched")。我有过这样的混乱:
template<class Pack, class Op>
struct Foldable
{
mystery_trait_t<Pack> value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(static_cast<std::decay_t<Pack>>(
(op.f)(std::move(value), std::move(rhs.value))
));
}
operator mystery_trait_t<Pack> () && {
return std::move(value);
}
};
template<class Pack>
auto NamedOperator::operator()(Pack&& value) const {
return Foldable<Pack, NamedOperator>(std::forward<Pack>(value), *this);
}
and(困惑了一会儿,然后开始问一个 SO 问题,找到这个现有的 question/answer,并在我的 mystery_trait_t
实现中添加一个 static_assert
到验证它实际上从未被右值引用类型调用过!)结果我真正需要的只是
template<class Pack, class Op>
struct Foldable
{
Pack value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(
(op.f)(std::move(value), std::move(rhs.value))
);
}
operator Pack () && {
return std::move(value);
}
};
(See my whole code on Wandbox.)
我的 "answer" 没有提供任何新信息,但我认为分享它会很有用,因为它只是表明即使您认为自己是 在模板元编程中深入并且确定你需要这种"conditional decay"行为......你真的不需要它!
可能有一个必然的一般规则,即 编写 any_template<T&&>
始终是一种代码味道。 在 Vittorio 的原始问题中,他实际上做了两次,尽管两次都是被 decltype
语法隐藏:
some_type_trait<decltype(xs)>... // should have been `Ts...`
std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...`
我正在尝试编写一个 returns 形式为 std::tuple
的可变参数包子集的函数。理想情况下,该函数应该没有运行时开销(没有不必要的副本),并且它应该允许用户访问 lvalue
引用并修改它们。
值类型、lvalue
引用和 const lvalue
引用应保留。临时对象(rvalue
引用)应 "converted" 到值类型以避免创建无效引用(对临时对象的引用)。
期望结果示例:
int lr = 5;
const int& clr = lr;
auto t = make_subpack_tuple(lr, clr, 5);
static_assert(is_same
<
decltype(t),
std::tuple<int&, const int&, int>
>{}, "");
// Ok, modifies lr:
std::get<0>(t) = 10;
// Compile-time error, intended:
// std::get<1>(t) = 20;
// Ok, 5 was moved into the tuple:
std::get<2>(t) = 30;
不完整实施示例:
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple
<
some_type_trait<decltype(xs)>...
>
(
std::forward<decltype(xs)>(xs)...
);
}
我想做的事情有意义吗?
有没有标准的类型特征可以用来代替 some_type_trait
?还是我应该实施自己的解决方案?
适合您的解决方案是
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple<Ts...>(std::forward<Ts>(xs)...);
}
根据 template argument deduction rules, the parameter pack Ts...
will contain only cv-qualified types and lvalues. The information in this question 也可能有用。
我只想说,我 运行 在实现 Nick Athanasios's foldable Op<operation>
的高效版本时遇到了同样的不是真正的问题 ("I think I need to decay rvalue references and keep lvalue references untouched")。我有过这样的混乱:
template<class Pack, class Op>
struct Foldable
{
mystery_trait_t<Pack> value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(static_cast<std::decay_t<Pack>>(
(op.f)(std::move(value), std::move(rhs.value))
));
}
operator mystery_trait_t<Pack> () && {
return std::move(value);
}
};
template<class Pack>
auto NamedOperator::operator()(Pack&& value) const {
return Foldable<Pack, NamedOperator>(std::forward<Pack>(value), *this);
}
and(困惑了一会儿,然后开始问一个 SO 问题,找到这个现有的 question/answer,并在我的 mystery_trait_t
实现中添加一个 static_assert
到验证它实际上从未被右值引用类型调用过!)结果我真正需要的只是
template<class Pack, class Op>
struct Foldable
{
Pack value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(
(op.f)(std::move(value), std::move(rhs.value))
);
}
operator Pack () && {
return std::move(value);
}
};
(See my whole code on Wandbox.)
我的 "answer" 没有提供任何新信息,但我认为分享它会很有用,因为它只是表明即使您认为自己是 在模板元编程中深入并且确定你需要这种"conditional decay"行为......你真的不需要它!
可能有一个必然的一般规则,即 编写 any_template<T&&>
始终是一种代码味道。 在 Vittorio 的原始问题中,他实际上做了两次,尽管两次都是被 decltype
语法隐藏:
some_type_trait<decltype(xs)>... // should have been `Ts...`
std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...`