11

STL準拠のコンテナであるタイプの場合、メンバー関数が含まれているCかどうかを正しく検出するにはどうすればよいですか?私は次のアプローチを試しました(GCC 4.6.3で):Creserve

template< typename C, typename = void >
struct has_reserve
  : std::false_type
{};

template< typename C >
struct has_reserve< C, typename std::enable_if<
                         std::is_same<
                           decltype( &C::reserve ),
                           void (C::*)( typename C::size_type )
                         >::value
                       >::type >
  : std::true_type
{};

これは、であるために機能しますCstd::vector、順序付けされていないコンテナでは機能しませんstd::unordered_set。その理由は、これreserveはの(直接)メンバー関数ですstd::vectorが、順序付けされていないコンテナの場合、基本クラスから継承されます。つまり、そのシグネチャはvoid (C::*)( typename C::size_type )void (B::*)( typename C::size_type )の一部の不特定の基本クラスBの署名ではありませんC

私はそれを回避し、reserve継承されたとしても検出する方法を知っていますが、それは不器用に見え、標準で何が許可されているのだろうかと思います。それで...

私の質問は次のとおりです。標準はreserve、指定されていない基本クラスから継承することを許可しますか、それとも概要をバインドし、直接メンバー関数を必要としますか?

4

1 に答える 1

12

基本クラスからの継承について標準で述べられているのは、それが許可されているということだけです。

17.6.5.11派生クラス[派生]

1-実装は、実装に予約されている名前のクラスからC++標準ライブラリ内の任意のクラスを派生させることができます。

メソッド(そして実際、typedefなどの他のメンバー)が基本クラスから継承できるかどうかは、どちらの方法でもわかりません。明らかに、実装はそうするので、標準はこの振る舞いを説明する必要があります。

いずれにせよ、たとえばreserveメンバー関数型へのキャストによる検出は、最も派生した型のメンバーであっても、機能することが保証されていません。理由は次のとおりです。

17.6.5.5メンバー関数[member.functions]

2-実装は、クラス内で追加の非仮想メンバー関数シグネチャを宣言できます。

  • デフォルト値の引数をメンバー関数のシグネチャに追加することによって186 ; [...]

186)したがって、C++標準ライブラリのクラスのメンバー関数のアドレスの型は指定されていません。

存在するかどうかを確認する正しい方法reserveは、それを呼び出そうとすることです。

template< typename C, typename = void >
struct has_reserve
  : std::false_type
{};

template< typename C >
struct has_reserve< C, typename std::enable_if<
                         std::is_same<
                           decltype( std::declval<C>().reserve( std::declval<typename C::size_type>() ) ),
                           void
                         >::value
                       >::type >
  : std::true_type
{};

これには、コンテナ要件(の表103 unordered_set)を並列化するという利点があります。これは、概要がより有益な傾向がある場合に標準的です。

于 2013-02-14T21:11:33.533 に答える