2011-10-25 16 views
7

Tener este código:plantillas variadic - incompleta de tipo

template<class ...Args> 
struct Are_Same 
{ 
    enum {value = Are_Same<Args...>::value}; 
}; 

template<class A,class... C> 
struct Are_Same<A,C...> 
{ 
    enum {value = Are_Same<A,C...>::value};//HERE is THE ERROREOUS LINE 
}; 

template<class A,class B> 
struct Are_Same<A,B> 
{ 
    enum {value = std::is_same<A,B>::value}; 
}; 

estoy recibiendo el error de gcc 4.6.1:

error: incomplete type 'Are_Same' used in nested name specifier.

pensé que haciendo Are_Same<A,C...>::value voy a invocar la llamada recursiva en la que el final simplemente se expandirá a Are_Same<A,B>. Obviamente no es el caso. ¿Alguien sabe dónde estoy cometiendo un error?

Respuesta

8

Creo que las definiciones de las plantillas son incorrectas, en ambos casos está activando la recursión exacta. Yo habría esperado que el compilador para que con un poco de stackoverflow dentro del compilador, pero se produce un error diferente ...

Una implementación de la plantilla variadic are_same podría ser:

template <class... Args>     // base (optional to declare the template) 
struct are_same; 

template <class A, class B, class... Args> // recursion 
struct are_same<A,B,Args...> { 
    static const bool value = is_same<A,B>::value && are_same<A,Args...>::value; 
}; 

template <class A, class B>     // stop condition 
struct are_same<A,B> { 
    static const bool value = is_same<A,B>::value; 
}; 

Tenga en cuenta que en el paso recursion , se quita un argumento de la lista de argumentos, de modo que el nuevo problema que se resolverá es una versión reducida de del original. Este tipo de metaprogramación de plantillas está bastante relacionada con la recursión, y se aplican las mismas reglas, para poder utilizar la recursión debe asegurarse de que cada paso recursivo lo acerque a una solución. En este caso particular, dada una lista de N tipos potencialmente iguales, cada paso reduce el problema para encontrar si los tipos N-1 son los mismos.

Se puede utilizar alternativamente, como condición de parada (en sustitución de la anterior) una versión degenerada del problema are_same:

template <class A> 
struct are_same<A> { 
    static const bool value = true; 
}; 

Cuál es degenerada en el sentido de que no tiene mucho sentido preguntar si un solo tipo * are_same *, pero para diferentes tareas de metaprogramación podría ser apropiado.

Un algoritmo potencialmente más eficiente diferente (no estoy seguro de si el compilador evitará la creación de instancias de la plantilla en el paso de recursión arriba) que no depende de is_same podría ser:

template <class... Args> 
struct are_same; 

template <class A, class... Args> 
struct are_same<A,A,Args...> {    // recursion 
    static const bool value = are_same<A,Args...>::value; 
}; 

template <class A, class B, class... Args> 
struct are_same<A,B,Args...> {    // cut, A and B are not the same 
    static const bool value = false; 
}; 

template <class A> 
struct are_same<A> {      // end of recursion 
    static const bool value = true; 
}; 

En este caso , el compilador preferirá los pasos recursion a cut cuando los dos tipos sean iguales, por lo que no es necesario que verifique is_same internamente. Al mismo tiempo, si el compilador entra en el paso cut, no es necesario que procesemos el resto de la lista de tipos, ya que ya conocemos la respuesta.

+1

que está volviendo loco brillante, especialmente el "cortocircuito" paso. Gracias. – smallB

+0

Bueno, pero hay un pequeño error en el primer fragmento de código. Debe ser 'static const bool value = is_same :: value && are_same :: value;' –

+1

@VJo: Son exactamente iguales, una vez que se ha probado que 'A == B', recurrente con' 'o' 'no importa en absoluto, ni tendrá ninguna ventaja, que está provocando una nueva instancia de la plantilla y que en este momento el compilador va a resolver para cualquiera que sea el tipo de' A' y 'B' es (es decir, 'int ',' double' ...), ambos pedazos de código son exactamente iguales. –

3

lo haría así:

aplicación
#include <type_traits> 
#include <iostream> 

template <class... Args> 
struct are_same 
{ 
    static const bool value=true; 
}; 

template <class A, class B, class... Args> // recursion 
struct are_same<A,B,Args...> { 
    static const bool value = std::is_same<A,B>::value && are_same<B,Args...>::value; 
}; 

int main() 
{ 
    std::cout<< std::boolalpha << are_same<int>::value << std::endl; 
    std::cout<< std::boolalpha << are_same< int, int, int >::value << std::endl; 
    std::cout<< std::boolalpha << are_same< int, int, double, int >::value << std::endl; 
} 
+0

gracias me gusta el camino sin detener la condición. Buena cosa; 1 – smallB

+2

@smallB: Este contiene exactamente la misma condición de parada, es sólo oculta en el modelo general, sólo hay dos especializaciones, una para el paso genérica, uno para la condición de parada (en este caso la condición de parada se ve más * en general *, ya que es 'plantilla ' pero sólo será la mejor opción para el compilador cuando ya no se puede aplicar el 'paso recursion' (es decir, cuando hay un solo tipo) En mi caso Prefiero hacer la condición de parada más explícita ya que odio pensar y tengo que descubrir cómo/cuándo se detendrá la recursión, pero eso es solo preferencia. –

0

Probablemente más simple podría ser así:

template <typename... TList> 
struct are_same { constexpr static bool value = false; }; 

template <typename T, typename... TList> 
struct are_same<T, T, TList...> { 
    constexpr static bool value = are_same<T, TList...>::value; 
}; 

template <typename T> 
struct are_same<T> { constexpr static bool value = true; }; 

Alternativamente, usted puede sustituir a condición de parada con

template <typename T> 
struct are_same<T, T> { constexpr static bool value = true; }; 

Pero la primera uno es más general porque are_same<type>::value == true. Otra pregunta es cómo debería ser are_same<>::value igual a. Esto le da false pero no es un gran problema agregar una especialización de plantilla más como esta.

template <> 
struct are_same<> { constexpr static bool value = true; }; 
Cuestiones relacionadas