проблема с шаблонами ('typename' не является параметром функции шаблона)

StackOverflow https://stackoverflow.com/questions/1600464

  •  05-07-2019
  •  | 
  •  

Вопрос

На самом деле у меня проблема с компиляцией некоторой библиотеки с помощью компилятора Intel.

Эта же библиотека была правильно скомпилирована с помощью g ++.

Проблема вызвана шаблонами.Что я хотел бы понять, так это объявление **typename** как не шаблонное объявление параметра функции и переменной внутри тела функции

пример:

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

Компиляция такого кода приводит к следующим ошибкам (intel), (gcc не утверждает):У меня есть следующие ошибки

../../../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())

Что я хотел бы понять, так это использование typename внутри тела функций, объявления параметров.

бывший.:

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());
    }

в другом файле у меня есть:

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;**
Это было полезно?

Решение

Вам нужно использовать typename для так называемых "зависимых типов".Это типы, которые зависят от аргумента шаблона и неизвестны до тех пор, пока не будет создан экземпляр шаблона.Вероятно, это лучше всего объяснить на примере:

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...
};

Это typedef определяющий barbar это тот, который требует typename для того, чтобы компилятор мог проверить шаблон на наличие явных синтаксических ошибок до того , как он создается с конкретным типом.Причина в том, что, когда компилятор видит шаблон в первый раз (когда он еще не создан с конкретными параметрами шаблона), компилятор не знает, является ли Foo::bar это тип.Насколько мне известно, я мог бы намереваться baz для создания экземпляров с типами, подобными этому

struct some_other_foo {
  static int bar;
};

в каком случае Foo::bar будет относиться к объект, не тип, а определение baz::bar это была бы синтаксическая бессмыслица.Не зная , является ли Foo::bar ссылается на тип, компилятор не имеет возможности проверить что-либо внутри baz это прямо или косвенно использует barbar даже для самых глупых опечаток, пока baz создается экземпляр.Используя надлежащий typename, baz выглядит примерно так:

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

  barbar f();

  // more stuff...
};

Теперь компилятор, по крайней мере, знает, что Foo::bar предполагается, что это имя типа, которое делает barbar имя типа тоже.Итак, декларация о f() синтаксически тоже все в порядке.

Кстати, есть аналогичная проблема с шаблонами вместо типов:

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

Когда компилятор "видит" Foo::bar он не знает, что это такое, так что bar<Foo с таким же успехом это могло бы быть сравнением, оставляющим компилятор в замешательстве по поводу конечного >.Здесь также вам нужно дать компилятору подсказку о том, что Foo::bar предполагается, что это имя шаблона:

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

Остерегайтесь:Примечательно, что Visual C ++ по-прежнему не реализует надлежащий двухфазный поиск (по сути:на самом деле он не проверяет шаблоны до тех пор, пока они не будут созданы).Поэтому он часто принимает ошибочный код, который пропускает typename или a template.

Другие советы

Смысл в том, typename ключевое слово должно сообщать компилятору, что что-то является именем типа, в ситуациях, когда это не очевидно.Возьмем этот пример:

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

Является T::foo тип, означающий, что мы объявляем указатель, или является T::foo статическая переменная, и мы выполняем умножение?

Поскольку компилятор понятия не имеет о том, каким может быть T на момент чтения шаблона, он понятия не имеет, какой из двух случаев правильный.

Стандарт предписывает, что компилятор должен предполагать последний случай и только интерпретировать T::foo в качестве имени типа , если ему предшествует typename ключевое слово, подобное этому:

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

В соответствии с вашим кодом:

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

Если приведенный выше код не является частью шаблона, то он не может быть скомпилирован с использованием g ++, за исключением старой версии g ++.

Как мой опытный, FC9 или GNU C / ++ версии 4.2x сообщат об этом как об ошибке, он будет жаловаться:

typename only can be used in template code

в то время как FC8 или GNU C /++ 4.1x не могут.

Пожалуйста, посмотрите

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

для получения дополнительных примеров шаблонов и имен типов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top