2010-11-03 13 views
12

considere el siguiente código:C++: clase anidada de una clase de plantilla

template < typename T > 
struct A 
{ 
    struct B { }; 
}; 

template < typename T > 
void f(typename A<T>::B) { } 

int main() 
{ 
    A<int>::B x; 
    f(x);   // fails for gcc-4.1.2 
    f<int>(x); // passes 
    return 0; 
} 

Así que aquí gcc-4.1.2 requiere el argumento de plantilla de f a especificar de forma explícita. ¿Es este el estándar? ¿Las versiones más nuevas de GCC tienen este problema solucionado? ¿Cómo puedo evitar especificar explícitamente int al llamar al f?

Actualización: Aquí hay una solución.

#include <boost/static_assert.hpp> 
#include <boost/type_traits/is_same.hpp> 

template < typename T > 
struct A 
{ 
    typedef T argument; 
    struct B { typedef A outer; }; 
}; 

template < typename T > 
void f(typename A<T>::B) { } 

template < typename Nested > 
void g(Nested) 
{ 
    typedef typename Nested::outer::argument TT; 
    BOOST_STATIC_ASSERT((boost::is_same< typename A<TT>::B, Nested >::value)); 
} 

struct NN 
{ 
    typedef NN outer; 
    typedef NN argument; 
}; 

int main() 
{ 
    A<int>::B x; 
    NN y; 
    g(x); // Passes 
    g(y); // Fails as it should, note that this will pass if we remove the type check 
    f(x); // Fails as before 

    return 0; 
} 

Sin embargo, todavía no puedo ver por qué llaman f(x); no es válido. ¿Puedes referirte a algún punto en el estándar que dice que tal llamada debería ser inválida? ¿Puedes traer un ejemplo donde esa llamada es ambigua?

Respuesta

10
typename A<T>::B 

Aquí, T es en un contexto nondeduced, lo que significa que T no se puede deducir a partir del argumento de función.

El problema es que, en el caso general, existe una cantidad potencialmente infinita de tipos posibles T que podrían coincidir. Considere, por ejemplo, si en lugar de struct B { }; tenía typedef int B;.

+2

Gracias por su respuesta. ¿Por qué 'T' no se puede deducir del argumento de la función? ¿Puedes traer un ejemplo donde hay dos tipos para 'T' que coinciden con una llamada particular de' f'? ¿Quiere decir que para otra especialización de 'A' podría ser otro' typedef int B; 'en lugar de' struct B {}; '? No puedo ver por qué en este caso la llamada de 'f' debe ser ambigua. – Vahagn

0

¿Cómo puedo evitar especificar explícitamente int al llamar a f?

Necesitará un poco de ayuda de struct B.

template < typename T > 
struct A 
{ 
    struct B 
    { 
     static T getType(); // no impl required 
    }; 
}; 

#define mytypeof(T) (true?0:T) 

template < typename T, typename U > 
void f(T t, U) { } // U will be T of A<T>::B 

Llamarlo con lo siguiente:

f(x, mytypeof(x.getType())); 

Como alternativa, puede abstracta mytypeof(x.getType()) distancia mediante la introducción de otra función que las llamadas f, lo que podría tener el original f(x). p.ej.

template < typename T, typename U > 
void b(T t, U) { } // U will be T of A<T>::B 

template < typename T > 
void f(T t) 
{ 
    b(t, mytypeof(t)); 
} 

A continuación, puede llamar al f(x).

+1

Gracias por su respuesta. Agregar un parámetro adicional no funcionará para mí, porque en realidad superé operadores en lugar de 'f'. – Vahagn

4

¿Cómo puedo evitar especificar explícitamente int al llamar a f?

Simplemente haga B declaran su tipo

template < typename T > 
struct A 
{ 
    struct B { typedef A outer; }; 
}; 

clase de anidación A continuación, puede deducirlo.La siguiente historia tiene la plantilla externa, typedef del interior y un tipo de retorno

template<template<typename> class Outer, typename D, typename R = void > 
struct nesting { }; 

template<template<typename> class Outer, typename Arg, typename R> 
struct nesting< Outer, Outer<Arg>, R > { 
    typedef Arg arg1_type; 
    typedef R type; 
}; 

template < typename T > 
typename nesting<A, typename T::outer>::type 
f(T) { 
    /* nesting<A, typename T::outer>::arg1_type is A's T */ 
} 
0

Siguiendo con la cuestión de la "actualización", aquí es una situación en la que la llamada a f sería ambigua (si se le permitiera , se entiende):

// Definitions of generic "struct A", as well as "f()", are the same as above 

// But additionally, consider a specialized "struct A", defined as follows: 

template <> 
struct A<double> 
{ 
    typedef A<int>::B B; 
} 

// Now consider the call to "f", similarly to before: 

int main() 
{ 
    // Possibility 1 for argument to "f()" 
    // A<int>::B x; 

    // Possibility 2 for argument to "f()": Use the specialized version of "struct A" 
    A<double>::B x; 

    f(x); // which value to deduce for type T? Could be "int" or "double" 
} 

Aviso el par ambigua de funciones potenciales instanciados f: Tanto f<int>() y f<double> daría lugar a una llamada exitosa a f().

Cuestiones relacionadas