元素方式元组添加

Pru*_*ica 30 c++ tuples

我在元组中有一些值,我希望在元素方面添加另一个元组.所以我想要这样的功能:

std::tuple<int,int> a = {1,2};
std::tuple<int,int> b = {2,4};


std::tuple<int,int> c = a + b; // possible syntax 1
a += b; // possible syntax 2
a += {2,4}; // possible syntax 3
Run Code Online (Sandbox Code Playgroud)

输出元组将具有该值的位置 {3,6}

正在看CPP参考,但我找不到这个功能.这个这个问题可能是相关的,但是其他复杂性会使答案变得模糊不清.

Vis*_*kar 28

你也可以考虑使用std :: valarray,因为它允许你想要的东西.

#include <valarray>

int main()
{
    std::valarray<int> a{ 1, 2 }, b{ 2, 4 }, c;
    c = a - b; // c is {-1,-2}
    a += b; // a is {3,6}
    a -= b; // a is {1,2} again
    a += {2, 4}; // a is {3,6} again
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 你现在经常看不到`std :: valarray`.Upvoted.明显的缺点是它的动态与`std :: tuple`相反. (11认同)
  • 这似乎是一个很好的解决方案.缺点是,如果我们有`std :: valarray <int> d {2,4,3};`,那么`a - = d; // a是{1,2}`和`d - = b; // d是{3,0,0},这是一些人可能会发现违反直觉的行为 (3认同)

Sim*_*mer 11

你可以使用这样的东西,它支持你的所有三个语法提议:

#include <tuple>
#include <utility>

namespace internal
{
    //see: https://stackoverflow.com/a/16387374/4181011
    template<typename T, size_t... Is>
    void add_rhs_to_lhs(T& t1, const T& t2, std::integer_sequence<size_t, Is...>)
    {
        auto l = { (std::get<Is>(t1) += std::get<Is>(t2), 0)... };
        (void)l; // prevent unused warning
    }
}

template <typename...T>
std::tuple<T...>& operator += (std::tuple<T...>& lhs, const std::tuple<T...>& rhs)
{
    internal::add_rhs_to_lhs(lhs, rhs, std::index_sequence_for<T...>{});
    return lhs;
}

template <typename...T>
std::tuple<T...> operator + (std::tuple<T...> lhs, const std::tuple<T...>& rhs)
{
   return lhs += rhs;
}
Run Code Online (Sandbox Code Playgroud)

工作范例:

http://coliru.stacked-crooked.com/a/27b8cf370d44d3d5

http://coliru.stacked-crooked.com/a/ff24dae1c336b937


在大多数情况下,我仍然会使用命名结构.元组很少是正确的选择.

  • 很好,但是对于我的理解:你为什么不做`std :: tuple <T ...> operator +(std :: tuple <T ...> lhs,const std :: tuple <T ...>& rhs){return lhs + = rhs; }`? (2认同)

Dei*_*Dei 8

@lubgr的解决方案对您的特定用例非常满意.我为您提供了一个通用的解决方案,适用于不同类型的元组,以及不同(相同)大小的元组.

#include <tuple>
#include <utility>
#include <iostream>

template<typename... T1, typename... T2, std::size_t... I>
constexpr auto add(const std::tuple<T1...>& t1, const std::tuple<T2...>& t2, 
                   std::index_sequence<I...>)
{
    return std::tuple{ std::get<I>(t1) + std::get<I>(t2)... };
}

template<typename... T1, typename... T2>
constexpr auto operator+(const std::tuple<T1...>& t1, const std::tuple<T2...>& t2)
{
    // make sure both tuples have the same size
    static_assert(sizeof...(T1) == sizeof...(T2));

    return add(t1, t2, std::make_index_sequence<sizeof...(T1)>{});
}
Run Code Online (Sandbox Code Playgroud)

我使用了一些C++ 17特性(主要是模板相关的),没有它们,代码会变得有点复杂.可能的改进是使用移动语义.

显然,这适用于您提供的第一个"可能的语法".

  • 也许考虑将`operator +`的参数指定为元组,因此它不会与其他泛型`operator +`定义冲突.`template <typename ... Args> constexpr auto operator +(const std :: tuple <Args ...>&t1,const std :: tuple <Args ...>&t2)`.这样你也不需要在两个元组的相同大小上断言. (3认同)