проблема с шаблонами («typename» как параметр функции шаблона) - PullRequest
4 голосов
/ 21 октября 2009

На самом деле у меня проблема с компиляцией некоторой библиотеки с помощью компилятора 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;**

Ответы [ 3 ]

13 голосов
/ 21 октября 2009

Вам необходимо использовать 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 или template.

4 голосов
/ 21 октября 2009

Смысл ключевого слова typename состоит в том, чтобы сообщить компилятору, что что-то является 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.
}
0 голосов
/ 21 октября 2009

По вашему коду:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...