删除右值,保持左值引用(标准类型特征可用吗?)

时间:2015-10-29 17:52:24

标签: c++ c++14 rvalue-reference typetraits perfect-forwarding

我尝试编写一个函数,该函数以std::tuple的形式返回可变参数包的子集。理想情况下,该函数应该没有运行时开销(没有不必要的副本),它应该允许用户访问lvalue引用并修改它们。

应维护值类型,lvalue引用和const lvalue引用。 Temporaries(rvalue引用)应该被转换为"值类型以避免创建无效引用(对临时引用的引用)。

期望结果的示例:

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的标准类型特征?或者我应该实施自己的解决方案?

2 个答案:

答案 0 :(得分:7)

您的解决方案将是

template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
    return std::tuple<Ts...>(std::forward<Ts>(xs)...);
}

根据template argument deduction rules,参数包Ts...将仅包含cv限定类型和左值。 this question中的信息也可能有用。

答案 1 :(得分:1)

我想说的是,我遇到了同样不是真正的问题(&#34;我认为我需要衰减右值引用并保持左值引用未被触及&#34;) Nick Athanasios's foldable Op<operation>的高效版本。我遇到了这个烂摊子:

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);
}

和(稍微疑惑一下,然后开始提出一个问题,并找到现有的问题/答案,并在static_assert的实施中添加mystery_trait_t来验证它是从来没有用rvalue引用类型实际调用!)事实证明我实际需要的只是

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.)

这个&#34;答案&#34;我没有提供任何新信息,但我认为分享是有用的,因为它只是表明即使你认为你在模板元编程中深入 确定你需要这个&#34;有条件的衰变&#34;行为......你真的不需要它!

可能有一个必然的一般规则,写作any_template<T&&>始终是代码气味。在维托里奥的原始问题中,他有效地做了两次,尽管两次都是隐藏decltype语法:

some_type_trait<decltype(xs)>...  // should have been `Ts...`
std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...`