problema templates ( 'typename' como parâmetro de função não template)
-
05-07-2019 - |
Pergunta
Na verdade, eu tenho um problema com a compilação de alguma biblioteca com o compilador Intel.
Esta mesma biblioteca foi compilada corretamente com g ++.
O problema é causado por modelos.
O que eu gostaria de entender é a declaração de
**typename**
como não template parâmetro de função e declaração variável dentro do corpo da função
exemplo:
void func(typename sometype){..
...
typename some_other_type;
..
}
Compilation este tipo de produto código a seguir erros (Intel), (gcc não reivindica a): Eu tenho seguinte erros
../../../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())
O que eu gostaria de entender é o uso do typename dentro do corpo de funções, declarações de parâmetro.
ex:.
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());
}
no arquivo diferente eu tenho:
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;**
Solução
Você precisa usar typename
para os chamados "tipos dependentes". Esses são os tipos que dependem de um argumento de modelo e não são conhecidos até que o modelo é instanciado. É provavelmente melhor explicado usando um exemplo:
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...
};
Isso typedef
definir barbar
é aquele que exige um typename
para que o compilador para ser capaz de verificar o modelo para erros sintácticos flagrantes antes é instanciado com um tipo concreto. A razão é que, quando o compilador vê o modelo pela primeira vez (quando não é instanciado com parâmetros do modelo concreto ainda), o compilador não sabe se Foo::bar
é um tipo. Por tudo o que sabe, eu poderia baz
intenção de ser instanciado com tipos como este
struct some_other_foo {
static int bar;
};
caso em que Foo::bar
remete a um objeto , e não um tipo, ea definição de baz::bar
seria absurdo sintática. Sem saber se Foo::bar
refere-se a um tipo, o compilador não tem nenhuma possibilidade de verificar qualquer coisa dentro baz
que está direta ou indiretamente usando barbar
mesmo para os mais erros estúpidos até baz
é instanciado. Usando o typename
adequada, baz
esta aparência:
template< typename Foo >
struct baz {
typedef typename Foo::bar barbar;
barbar f();
// more stuff...
};
Agora, o compilador pelo menos sabe que Foo::bar
é suposto ser o nome de um tipo, o que torna barbar
um nome de tipo, também. Assim, a declaração de f()
é sintática OK, também.
A propósito, há um problema semelhante com modelos em vez de tipos:
template< typename Foo >
struct baz {
Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile
};
Quando o compilador "vê" Foo::bar
ele não sabe o que é, por isso bar<Foo
poderia muito bem ser uma comparação, deixando o compilador confuso sobre o >
final. Aqui, também, você precisa dar o compilador uma dica que Foo::bar
é suposto ser o nome de um modelo:
template< typename Foo >
struct baz {
Foo::template bar<Foo> create_wrgl();
};
Cuidado: Notavelmente Visual C ++ continua a não implementar a pesquisa de duas fases apropriado (em essência: ele realmente não se verifique modelos até que sejam instanciado). Mesmos que muitas vezes aceita código errônea de que perde uma typename
ou um template
.
Outras dicas
O ponto da palavra-chave typename
é para dizer ao compilador que algo é uma typename, em situações em que não é óbvio. Veja este exemplo:
template<typename T>
void f()
{
T::foo * x;
}
É T::foo
um tipo, ou seja, estamos declarando um ponteiro, ou é T::foo
uma variável estática, e estamos fazendo uma multiplicação?
Uma vez que o compilador não tem idéia do que T pode ser no momento em que lê o modelo, ele não tem idéia de qual dos dois casos está correto.
Os ditames padrão que o compilador deve assumir último caso, e somente interpretar T::foo
como um typename se for precedido pela palavra-chave typename
, como este:
template<typename T>
void f()
{
typename T::foo* x; //Definitely a pointer.
}
Ao seu código:
void func(typename sometype)
{
.....typename some_other_type;
..
}
Se o código acima não é uma parte de um modelo, então não pode ser compilado usando g ++, a menos que a versão antiga do g ++.
Como o meu experiente, FC9 ou GNU C / ++ versão 4.2 x irá relatá-lo como um erro, ele vai reclamar:
typename only can be used in template code
enquanto FC8 ou GNU C / ++ 4.1x não pode.
Por favor, veja
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 obter mais exemplos de modelos e TypeName.