Vorlagen Problem ( ‚Typname‘ als nicht Template-Funktion Parameter)
-
05-07-2019 - |
Frage
Eigentlich habe ich ein Problem mit etwas Bibliothek mit Intel-Compiler kompiliert wird.
Die gleiche Bibliothek wurde ordnungsgemäß mit g ++ kompiliert.
Problem wird durch Vorlagen verursacht.
Was ich möchte, verstehen, ist die Erklärung von
**typename**
als nicht Template-Funktion Parameter und Variablendeklaration innerhalb Funktionskörper
Beispiel:
void func(typename sometype){..
...
typename some_other_type;
..
}
Compilation diese Art von Code produzieren folgende Fehler (Intel), (gcc behauptet nicht): Ich habe folgende Fehler bekam
../../../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())
Was ich möchte, verstehen, ist die Verwendung des Typnamen im Innern des Körpers von Funktionen, Parameterdeklarationen.
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());
}
in verschiedener Datei Ich habe:
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;**
Lösung
Sie müssen typename
verwenden, um so genannte „abhängige Typen“. Das sind Typen, die auf einer Vorlage Argument abhängen und sind nicht bekannt, bis die Vorlage instanziiert wird. Es ist wahrscheinlich am besten erklärt anhand eines Beispiels:
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...
};
Die typedef
definiert barbar
ist eine, die ein typename
benötigt, um für die Compiler in der Lage sein, um die Vorlage zu prüfen eklatante syntaktische Fehler vor es ist mit einem konkreten Typ instanziiert. Der Grund dafür ist, dass, wenn der Compiler die Vorlage zum ersten Mal sieht (wenn es nicht mit konkretem Template-Parameter noch instanziiert), der Compiler nicht weiß, ob Foo::bar
ein Typ ist. Für alle es wissen, ich könnte Absicht baz
mit Typen wie diese auszuprägen
struct some_other_foo {
static int bar;
};
In diesem Fall Foo::bar
zu einem Objekt verweist , keinen Typ, und die Definition von baz::bar
würde syntaktischer Unsinn. Ohne zu wissen, ob Foo::bar
auf eine Art bezieht, hat der Compiler keine Chance etwas innerhalb baz
zu überprüfen, die direkt oder indirekt sind barbar
mit selbst für die dümmste Fehler bis baz
instanziiert wird. Mit Hilfe der richtigen typename
, baz
sieht wie folgt aus:
template< typename Foo >
struct baz {
typedef typename Foo::bar barbar;
barbar f();
// more stuff...
};
Jetzt ist der Compiler auf weiß wenigstens, dass Foo::bar
soll der Name einer Art sein, die barbar
ein Typname auch macht. So ist die Erklärung von f()
ist syntaktische auch OK.
Übrigens gibt es ein ähnliches Problem mit Vorlagen statt Typen:
template< typename Foo >
struct baz {
Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile
};
Wenn der Compiler „sieht“ Foo::bar
es nicht weiß, was es ist, so bar<Foo
könnte genausogut ein Vergleich sein, den Compiler verwirrt über den Hinter >
verlassen. Auch hier müssen Sie den Compiler einen Hinweis geben, dass Foo::bar
soll der Name einer Vorlage sein:
template< typename Foo >
struct baz {
Foo::template bar<Foo> create_wrgl();
};
Achtung: Bemerkenswerter Visual C ++ weiterhin nicht implementieren richtigen zweiphasige Lookup (im Wesentlichen: sie nicht wirklich Vorlagen überprüfen, bis sie instanziiert werden). Dafür ist es akzeptiert oft fehlerhaften Code, der ein typename
oder ein template
vermisst.
Andere Tipps
Der Punkt des typename
Schlüsselwort ist, den Compiler zu sagen, dass etwas ein Typname ist, in Situationen, in denen es nicht offensichtlich ist. Nehmen Sie dieses Beispiel:
template<typename T>
void f()
{
T::foo * x;
}
Ist T::foo
ein Typ, was bedeutet, wir einen Zeiger deklarieren, oder ist T::foo
eine statische Variable, und wir eine Multiplikation tun?
Da die Compiler keine Ahnung von dem, was T zu der Zeit sein, könnte es die Vorlage liest, sie keine Ahnung hat, welche die beiden Fälle korrekt ist.
Der Standard schreibt vor, dass der Compiler den letzteren Fall übernehmen sollte, und nur T::foo
als Typnamen interpretieren, wenn es durch das typename
Schlüsselwort, wie dies vorangestellt ist:
template<typename T>
void f()
{
typename T::foo* x; //Definitely a pointer.
}
Bei Ihrem Code:
void func(typename sometype)
{
.....typename some_other_type;
..
}
Wenn der obige Code nicht ein Teil einer Vorlage ist, dann kann es nicht g kompiliert werden ++ verwenden, es sei denn, die alte Version von g ++.
Wie meine Erfahrung, FC9 oder GNU C / ++ Version 4.2x es als Fehler berichten, wird es beklagen:
typename only can be used in template code
während FC8 oder GNU C / ++ 4.1x möglicherweise nicht.
Bitte beachten Sie
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
für weitere Vorlage und Typnamen Beispiele.