c++ - second - Elemento sabio adición de tupla
struct pair c++ (4)
Tengo algunos valores mantenidos en una tupla, y estoy buscando agregar otra tupla a ella de forma elemental. Así que me gustaría una funcionalidad como esta:
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
Donde la tupla de salida tendría el valor {3,6}
Estaba mirando la referencia de CPP , pero no pude encontrar esta funcionalidad. Es posible que this y this pregunta sean relevantes, sin embargo, las respuestas están oscurecidas por otras complejidades.
Aquí hay una definición de operador para la sintaxis n. ° 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));
}
La sintaxis n. ° 2 y n. ° 3 no son posibles sin crear una estructura personalizada, ya que solo pueden definirse como miembros de las clases en las que operan (y no puede tocar las clases existentes en el espacio de nombres std
).
La solución de @lubgr es satisfactoria para su caso de uso específico. Te ofrezco una solución genérica que funcionará para tuplas de diferentes tipos, así como tuplas de diferentes tamaños (iguales).
#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)>{});
}
Utilicé algunas características de C ++ 17 (principalmente relacionadas con plantillas) sin las cuales el código se volvería un poco más complicado. Una posible mejora sería hacer uso de la semántica de movimiento.
Obviamente, esto se aplica a la primera "sintaxis posible" que proporcionó.
Puede usar algo como esto, que admite las tres propuestas de sintaxis:
#include <tuple>
#include <utility>
namespace internal
{
//see: https://.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;
}
Ejemplo de trabajo:
http://coliru.stacked-crooked.com/a/27b8cf370d44d3d5
http://coliru.stacked-crooked.com/a/ff24dae1c336b937
Todavía iría con estructuras nombradas en la mayoría de los casos. Las tuplas rara vez son la elección correcta.
También podría considerar usar std::valarray ya que permite exactamente las cosas que parece querer.
#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;
}