29

https://stackoverflow.com/a/1967183/134841では、メンバーが存在するかどうか、場合によってはタイプのサブクラスに存在するかどうかを静的にチェックするためのソリューションが提供されています。

template <typename Type> 
class has_resize_method
{ 
   class yes { char m;}; 
   class no { yes m[2];}; 
   struct BaseMixin 
   { 
     void resize(int){} 
   }; 
   struct Base : public Type, public BaseMixin {}; 
   template <typename T, T t>  class Helper{}; 
   template <typename U> 
   static no deduce(U*, Helper<void (BaseMixin::*)(), &U::foo>* = 0); 
   static yes deduce(...); 
public: 
   static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0))); 
};

ただし、C ++ 11finalクラスでは機能しません。これは、テスト対象のクラスから継承するためfinalです。

OTOH、これ:

template <typename C>
struct has_reserve_method {
private:
    struct No {};
    struct Yes { No no[2]; };
    template <typename T, typename I, void(T::*)(I) > struct sfinae {};
    template <typename T> static No  check( ... );
    template <typename T> static Yes check( sfinae<T,int,   &T::reserve> * );
    template <typename T> static Yes check( sfinae<T,size_t,&T::reserve> * );
public:
    static const bool value = sizeof( check<C>(0) ) == sizeof( Yes ) ;
};

reserve(int/size_t)ベースクラスでメソッドが見つかりません。

reserved()のベースクラスで検出され、そうであるT場合でも機能するこのメタ関数の実装はありTますfinalか?

4

2 に答える 2

51

decltype実際、C++11 ではと late return bindings 機構のおかげで物事がはるかに簡単になりました。

メソッドを使用してこれをテストする方が簡単です。

// Culled by SFINAE if reserve does not exist or is not accessible
template <typename T>
constexpr auto has_reserve_method(T& t) -> decltype(t.reserve(0), bool()) {
  return true;
}

// Used as fallback when SFINAE culls the template method
constexpr bool has_reserve_method(...) { return false; }

次に、これをクラスで使用できます。たとえば、次のようになります。

template <typename T, bool b>
struct Reserver {
  static void apply(T& t, size_t n) { t.reserve(n); }
};

template <typename T>
struct Reserver <T, false> {
  static void apply(T& t, size_t n) {}
};

そして、あなたはそれを次のように使用します:

template <typename T>
bool reserve(T& t, size_t n) {
  Reserver<T, has_reserve_method(t)>::apply(t, n);
  return has_reserve_method(t);
}

enable_ifまたは、次の方法を選択できます。

template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<has_reserve_method(t), bool>::type {
  t.reserve(n);
  return true;
}

template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<not has_reserve_method(t), bool>::type {
  return false;
}

この切り替えは実際にはそれほど簡単ではないことに注意してください。一般に、SFINAE だけが存在する場合ははるかに簡単です。また、enable_if1 つのメソッドのみを使用し、フォールバックを提供したくない場合は、次のようになります。

template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
  t.reserve(n);
}

置換が失敗した場合、このメソッドは可能なオーバーロードのリストから削除されます。

,注: (コンマ演算子)のセマンティクスのおかげで、複数の式を連鎖させることができdecltype、最後の式のみが実際に型を決定します。複数の操作を確認するのに便利です。

于 2012-03-02T10:00:25.987 に答える
10

decltype任意の型を [ に渡すことにも依存しているが、それに依存していないバージョン(...)[これは実際にはとにかく問題ではありません。ヨハネスのコメントを参照してください]:

template<typename> struct Void { typedef void type; };

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

template<typename T>
struct has_reserve<
    T
    , typename Void<
        decltype( std::declval<T&>().reserve(0) )
    >::type
>: std::true_type {};

std::vector<int>&この特性によれば、サポートするような型を指摘したいと思いreserveます。ここでは、型ではなく式が検査されます。この特性が答える質問は、「lvalそのような型の左辺値が与えられた場合T、式はlval.reserve(0);適切に形成されているか」です。「この型またはその基本型のいずれかにreserveメンバーが宣言されていますか」という質問と同じではありません。

一方、間違いなくそれは機能です!is_default_constructible新しい C++11 トレイトはではなく のスタイルであることを思い出してくださいhas_default_constructor。区別は微妙ですが、メリットがあります。is_*ible(演習として、左のスタイルでより適切な名前を見つけます。)

std::is_classいずれにせよ、あなたが望むものを達成する可能性があるなどの特性を使用することができます。

于 2012-03-03T08:54:48.880 に答える