テンプレートの問題(テンプレート関数パラメーターではない「タイプ名」)
-
05-07-2019 - |
質問
実際、一部のライブラリをインテルコンパイラでコンパイルするのに問題があります。
これと同じライブラリがg ++で適切にコンパイルされています。
問題はテンプレートが原因です。
私が理解したいのは、の宣言です
**typename**
関数本体内のテンプレート関数パラメーターおよび変数宣言ではありません
例:
void func(typename sometype){..
...
typename some_other_type;
..
}
この種のコードをコンパイルすると、次のエラー(インテル)が発生します(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())
理解したいのは、関数の本体内での型名の使用、パラメータ宣言です。
例:
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;**
解決
いわゆる<!> quot;依存型<!> quot;には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
は、コンパイラが具体的な型でインスタンス化される前に、明白な構文エラーのテンプレートをチェックできるようにするためにFoo::bar
を必要とするものです。 。その理由は、コンパイラが初めてテンプレートを見るとき(具体的なテンプレートパラメータでまだインスタンス化されていないとき)、コンパイラはbaz
が型であるかどうかを知らないからです。それが知っているすべてのために、私はbaz::bar
このようなタイプでインスタンス化されることを意図するかもしれません
struct some_other_foo {
static int bar;
};
この場合、f()
は型ではなくオブジェクトを参照し、bar<Foo
の定義は構文上のナンセンスです。 >
が型を参照しているかどうかがわからない場合、コンパイラはtemplate
がインスタンス化されるまで、最も愚かなタイプミスでも<=>を直接または間接的に使用して<=>内の何かをチェックする機会がありません。適切な<=>を使用すると、<=>は次のようになります。
template< typename Foo >
struct baz {
typedef typename Foo::bar barbar;
barbar f();
// more stuff...
};
少なくとも、コンパイラは<=>が型の名前であることを認識しており、これにより<=>も型名になります。したがって、<=>の宣言も構文上問題ありません。
ところで、型ではなくテンプレートにも同様の問題があります:
template< typename Foo >
struct baz {
Foo::bar<Foo> create_wrgl(); // wrong, shouldn't compile
};
コンパイラが<!> quot; sees <!> quot; <=>それはそれが何であるかを知らないので、<=>は比較であり、コンパイラーは末尾の<=>について混乱します。ここでも、コンパイラに<=>がテンプレートの名前になるはずであるというヒントを与える必要があります:
template< typename Foo >
struct baz {
Foo::template bar<Foo> create_wrgl();
};
注意:特に、Visual C ++はまだ適切な2フェーズルックアップを実装していません(本質的には、テンプレートがインスタンス化されるまで実際にはチェックしません)。そのため、多くの場合、<=>または<=>を逃す誤ったコードを受け入れます。
他のヒント
typename
キーワードのポイントは、明らかでない状況で、何かが型名であることをコンパイラーに伝えることです。次の例をご覧ください:
template<typename T>
void f()
{
T::foo * x;
}
T::foo
型、つまりポインターを宣言しているのですか、それとも<=>静的変数であり、乗算を実行しているのですか?
コンパイラーは、テンプレートを読み取る時点でTが何であるかわからないため、2つのケースのどちらが正しいかわかりません。
標準では、コンパイラは後者のケースを想定し、<=>キーワードが次のように先行する場合にのみ<=>を型名として解釈するように規定しています。
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
その他のテンプレートとタイプ名の例については