Actualmente estoy en el proceso de escribir sobrecargas de operadores aritméticos para tuplas. El operador itera sobre la tupla para realizar la operación en cada uno de sus elementos individuales. Aquí está la definición de operador + =:C++ - Iteración sobre una tupla y resolución de tipo vs parámetros constantes
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple<Ts...>& >::type operator +=(std::tuple<Ts...>& lhs, const std::tuple<Ts...>& rhs)
{
return lhs;
}
template< typename... Ts, std::size_t I = 0 >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple<Ts...>& >::type operator +=(std::tuple<Ts...>& lhs, const std::tuple<Ts...>& rhs)
{
std::get<I>(lhs) += std::get<I>(rhs);
return operator +=< Ts..., I + 1 >(lhs, rhs);
}
Por desgracia, cuando intento llamar al operador, GCC 4.6 no puede decidir qué sobrecargue debería usar. Por ejemplo:
std::tuple< int, int, int, int > a = std::make_tuple(1, 2, 3, 4), b = std::make_tuple(5, 6, 7, 8);
a += b;
produce el siguiente error:
:/Workspace/raster/main.cpp:833:7: instantiated from here
C:/Workspace/raster/main.cpp:809:45: error: no matching function for call to 'operator+=(std::tuple<int, int, int, int>&, const std::tuple<int, int, int, int>&)'
C:/Workspace/raster/main.cpp:809:45: note: candidates are:
C:/Workspace/raster/main.cpp:800:151: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I == sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
C:/Workspace/raster/main.cpp:806:83: note: template<class ... Ts, unsigned int I> typename std::enable_if<(I != sizeof (Ts ...)), std::tuple<_TElements ...>&>::type operator+=(std::tuple<_TElements ...>&, const std::tuple<_TElements ...>&)
lo cual es extraño ya que la condición std::enable_if
debe rechazar la llamada apropiada. Por ahora, tengo la siguiente solución que fue en realidad mi implementación anterior. La versión anterior es, de hecho, un intento de simplificación.
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I == sizeof... (Ts), std::tuple<Ts...>& >::type assignadd_impl(std::tuple<Ts...>& lhs, const std::tuple<Ts...>& rhs)
{
return lhs;
}
template< std::size_t I, typename... Ts >
inline typename std::enable_if< I != sizeof... (Ts), std::tuple<Ts...>& >::type assignadd_impl(std::tuple<Ts...>& lhs, const std::tuple<Ts...>& rhs)
{
std::get<I>(lhs) += std::get<I>(rhs);
return assignadd_impl< I + 1, Ts... >(lhs, rhs);
}
template< typename... Ts >
inline std::tuple<Ts...>& operator +=(std::tuple<Ts...>& lhs, const std::tuple<Ts...>& rhs)
{
return assignadd_impl< 0, Ts... >(lhs, rhs);
}
Esto compila y funciona como se esperaba. ¿Por qué la versión simplificada se niega a compilar? Gracias.
¿Qué sucede si mueve el parámetro de la plantilla 'I' al frente en su primer ejemplo de código, como en el segundo que funciona? ¿Eso cambia algo? –
@Jeremiah Willcock - Desafortunadamente no. Intenté muchas variaciones, incluido cambiar el orden de los parámetros de la plantilla, pero todos ellos producen el mismo error. – pmjobin