проблема с шаблонами ('typename' не является параметром функции шаблона)
-
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
для получения дополнительных примеров шаблонов и имен типов.