Pregunta

En realidad, tengo un problema al compilar alguna biblioteca con el compilador de inteligencia.

Esta misma biblioteca se ha compilado correctamente con g ++.

El problema es causado por las plantillas. Lo que me gustaría entender es la declaración de **typename** como no parámetro de función de plantilla y declaración de variable dentro del cuerpo de función

ejemplo:

void func(typename sometype){..
...
typename some_other_type;
..
}

La compilación de este tipo de código produce los siguientes errores (intel), (gcc no dice): Tengo los siguientes errores

../../../libs/log/src/attribute_set.cpp(415): error: no operator "!=" matches these operands
            operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'>
      while (begin != end)
                   ^
          detected during instantiation of "void boost::log_st::basic_attribute_set<CharT>::erase(boost::log_st::basic_attribute_set<CharT>::iter<'\000'>, boost::log_st::basic_attribute_set<CharT>::iter<'\000'>) [with CharT=wchar_t]" at line 438

../../../boost/log/attributes/attribute_set.hpp(115): error: no operator "!=" matches these operands
            operand types are: boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'> != boost::log_st::basic_attribute_set<wchar_t>::iter<'\000'>
              if (it != m_pContainer->end())

Lo que me gustaría entender es el uso del nombre de tipo dentro del cuerpo de funciones, declaraciones de parámetros.

ej .:

template< typename CharT >
struct basic_attribute_values_view< CharT >::implementation
{

public:
..
..
void adopt_nodes( **typename attribu**te_set_type::const_iterator& it, **typename attribut**e_set_type::const_iterator end)
    {
        for (; it != end; ++it)
            push_back(it->first, it->second.get());
    }

en un archivo diferente que he:

template< typename CharT >
class basic_attribute_set
{
    friend class basic_attribute_values_view< CharT >;

    //! Self type
    typedef basic_attribute_set< CharT > this_type;

public:
    //! Character type
    typedef CharT char_type;
    //! String type
    typedef std::basic_string< char_type > string_type;
    //! Key type
    typedef basic_slim_string< char_type > key_type;
    //! Mapped attribute type
    typedef shared_ptr< attribute > mapped_type;

    //! Value type
    typedef std::pair< const key_type, mapped_type > value_type;
    //! Allocator type
    typedef std::allocator< value_type > allocator_type;
    //! Reference type
    **typedef typename allocator_type::reference reference;**
¿Fue útil?

Solución

Debe usar typename para los llamados " tipos dependientes " ;. Esos son tipos que dependen de un argumento de plantilla y no se conocen hasta que se crea una instancia de la plantilla. Probablemente se explique mejor usando un ejemplo:

struct some_foo {
  typedef int bar;
};

template< typename Foo >
struct baz {
  typedef Foo::bar barbar; // wrong, shouldn't compile

  barbar f(); // would be fine if barbar were a type

  // more stuff...
};

Esa typedef definición de barbar es una que requiere un Foo::bar para que el compilador pueda verificar la plantilla en busca de errores sintácticos evidentes antes de que se instancia con un tipo concreto . La razón es que, cuando el compilador ve la plantilla por primera vez (cuando aún no se instancia con parámetros de plantilla concretos), el compilador no sabe si baz es un tipo. Por lo que sé, podría intentar baz::bar ser instanciado con tipos como este

struct some_other_foo {
  static int bar;
};

en cuyo caso f() se referiría a un objeto , no a un tipo, y la definición de bar<Foo sería un sinsentido sintáctico. Sin saber si > se refiere a un tipo, el compilador no tiene la posibilidad de verificar nada dentro de template que esté usando directa o indirectamente <=> incluso para los errores más estúpidos hasta que se instancia <=>. Usando el <=> apropiado, <=> se ve así:

template< typename Foo >
struct baz {
  typedef typename Foo::bar barbar;

  barbar f();

  // more stuff...
};

Ahora el compilador al menos sabe que se supone que <=> es el nombre de un tipo, lo que hace que <=> también sea un nombre de tipo. Entonces, la declaración de <=> también es sintáctica.

Por cierto, hay un problema similar con las plantillas en lugar de los tipos:

template< typename Foo >
struct baz {
  Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile
};

Cuando el compilador " ve " <=> no sabe lo que es, por lo que <=> podría ser una comparación, dejando al compilador confundido acerca del <=> final. Aquí, también, debe darle al compilador una pista de que se supone que <=> es el nombre de una plantilla:

template< typename Foo >
struct baz {
  Foo::template bar<Foo> create_wrgl();
};

Cuidado: Notablemente, Visual C ++ todavía no implementa la búsqueda de dos fases adecuada (en esencia: en realidad no verifica las plantillas hasta que se instancian). Por lo tanto, a menudo acepta código erróneo que pierde un <=> o un <=>.

Otros consejos

El objetivo de la palabra clave typename es decirle al compilador que algo es un nombre de tipo, en situaciones donde no es obvio. Tome este ejemplo:

template<typename T>
void f()
{
    T::foo * x;
}

¿Es T::foo un tipo, lo que significa que estamos declarando un puntero, o es <=> una variable estática y estamos haciendo una multiplicación?

Dado que el compilador no tiene idea de qué T podría ser en el momento en que lee la plantilla, no tiene idea de cuál de los dos casos es correcto.

El estándar dicta que el compilador debe asumir el último caso, y solo interpretará <=> como un nombre de tipo si está precedido por la palabra clave <=>, como esta:

template<typename T>
void f()
{
    typename T::foo* x; //Definitely a pointer.
}

Sobre su código:

void func(typename sometype)
{
    .....typename some_other_type;
    ..
}

Si el código anterior no es parte de una plantilla, entonces no puede compilarse usando g ++, a menos que la versión anterior de g ++.

Como mi experimentado, FC9 o GNU C / ++ versión 4.2x lo informará como un error, se quejará:

typename only can be used in template code

mientras que FC8 o GNU C / ++ 4.1x pueden no.

Por favor vea

http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/ringed_inl.h
and 
http://code.google.com/p/effocore/source/browse/trunk/devel/effo/codebase/addons/inl/include/cont_inl.h

para obtener más ejemplos de plantillas y nombres de tipos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top