2011-01-28 9 views
9

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.

+0

¿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? –

+0

@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

Respuesta

4

El uso explícito de argumentos de plantilla para una plantilla de función o clase requiere que todos los paquetes de parámetros de plantilla aparezcan al final de la lista de parámetros de plantilla general. Mover Ts... hasta el final de las listas de parámetros de plantilla y cambiar las llamadas de forma adecuada hace que el código funcione. La sección 14.8.2.1 de the current C++0x draft indica que los paquetes de parámetros que no están al final de la lista de parámetros de plantilla no se pueden deducir de una llamada a función (que hace que el código original falle), pero especifica todos los argumentos de plantilla a operator+= en todos los casos todavía causa un error SFINAE. A previous question tiene un enlace al texto exacto que lo prohíbe; IBM's documentation dice que es un error también.

+0

Realmente funciona. No sé qué salió mal durante mis pruebas originales porque tenía argumentos de plantilla invertidos en un punto. Pero gracias de todos modos. :) – pmjobin