按元素添加元组

Element-wise tuple addition

本文关键字:元组 添加 元素      更新时间:2023-10-16

我在元组中保存了一些值,我希望按元素向其添加另一个元组。 所以我想要这样的功能:

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

其中输出元组的值{3,6}

正在查看 CPP 参考,但我找不到此功能。 这个问题和这个问题可能是相关的,但是答案被其他复杂性所混淆。

你也可以考虑使用 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;
}

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

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

工作示例:

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

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


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

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

我使用了一些 C++17 功能(主要是与模板相关的功能(,如果没有这些功能,代码会变得更加复杂。一个可能的改进是利用移动语义。

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

下面是语法 #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));
}

如果不创建自定义结构,语法 #2 和 #3 是不可能的,因为它们只能定义为它们所操作的类的成员(并且您不能接触命名空间std中的现有类(。