Element-wise tuple addition

前端 未结 4 778
后悔当初
后悔当初 2021-02-06 23:29

I have some values held in a tuple, and I am looking to add another tuple to it element-wise. So I would like functionality like this:

std::tuple         


        
相关标签:
4条回答
  • 2021-02-06 23:34

    The solution by @lubgr is satisfactory for your specific use-case. I offer you a generic solution which will work for tuples of different types, as well tuples of different (equal) sizes.

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

    I used a few C++17 features (mainly template-related) without which the code would become a bit more complicated. A possible improvement would be to make use of move-semantics.

    Obviously, this applies for the first "possible syntax" you provided.

    0 讨论(0)
  • 2021-02-06 23:35

    You could also consider using std::valarray since it allows exactly the things that you seem to want.

    #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;
    }
    
    0 讨论(0)
  • 2021-02-06 23:45

    Here is an operator definition for syntax #1:

    template <class S, class T> std::tuple<S, T> operator + (const std::tuple<S, T>& lhs, const std::tuple<S, T>& rhs)
    {
       return std::make_tuple(std::get<0>(lhs) + std::get<0>(rhs), std::get<1>(lhs) + std::get<1>(rhs));
    }
    

    Syntax #2 and #3 are not possible without creating a custom struct, because they can only be defined as members of the classes they operate on (and you can't touch existing classes in namespace std).

    0 讨论(0)
  • 2021-02-06 23:54

    You could use something like this, which supports all three of your syntax proposals:

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

    Working example:

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

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


    I would still go with named structs in most cases. Tuples are seldom the correct choice.

    0 讨论(0)
提交回复
热议问题