テンプレートの問題(テンプレート関数パラメーターではない「タイプ名」)

StackOverflow https://stackoverflow.com/questions/1600464

  •  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

その他のテンプレートとタイプ名の例については

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top