3

型が特定のCRTP基本クラスから派生しているかどうかを判断するためis_fooに、で使用できる関数を作成しようとしています。enable_if以下のコードは、is_foo関数を実装するための私の試みですが、実際には機能しません。誰かがそれを修正するために何を変更する必要があるか教えてもらえますか?

ありがとう。

#include <iostream>
#include <type_traits>
#include <functional>

using namespace std;

template <class Underlying, class Extra>
struct Foo
{
    int foo() const { return static_cast<const Underlying*>(this)->foo(); }
};

template<class T>
struct Bar : Foo<Bar<T>, T>
{
    int foo() const { return 42; }
};

template<class T>
struct is_foo { static const bool value = false; };

template<class Underlying, class Extra>
struct is_foo<Foo<Underlying, Extra> > { static const bool value = true; };

template<class T>
void test(const T &t)
{
    cout << boolalpha << is_foo<T>::value << endl;
}

int main()
{
    Bar<int> b;
    test(b);
}
4

2 に答える 2

3

typedef を Foo ベースに追加します。

template < typename Derived >
struct crtp
{
  ...
  typedef int is_crtp;
};

has_field チェックを実装します。

BOOST_MPL_HAS_XXX(is_crtp)

メタ関数を実装します。

template < typename T >
struct is_crtp_derived : has_is_crtp<T> {};

これが、孫を正しく捕まえる唯一の方法だと思います。ただし、誤検知が発生しやすいため、他の場所で誤って使用されないように、あまりにも不快な名前を選択する必要があります. 他のオプションは、is_base_of に関してメタ関数を実装することです。

template < typename T >
struct is_crtp_derived : std::is_base_of< crtp<T>, T> {};

もちろん、これは孫を捕まえません。

于 2011-02-22T00:53:38.700 に答える
0

次のようにできます。

typedef char (&yes)[1];
typedef char (&no )[2];


template<class container>
struct class_helper
{
    template<typename member> static no  has_implemented(member);
    template<typename member> static yes has_implemented(member container::*);  
};


template<class derived>
class base
{
protected:
    base() {}

public:
    void foo() 
    {
        static_assert(
            sizeof(class_helper<derived>::has_implemented(&derived::foo)) == sizeof(yes),
            "derived::foo not implemented"
        );
        static_cast<derived*>(this)->foo();
    }
};

ただし、定義したインターフェイス関数ごとに static_assert を実行する必要があります。enable_if を使用して、より一般的にすることができます。

static_cast<typename enable_if_c<
    sizeof(class_helper<derived>::has_member(&derived::foo)) == sizeof(yes), derived
>::type*>(this)->foo();

この手法には、「派生」で「foo」が実装されていない場合に、紛らわしいコンパイラ エラーに対処しなければならないという欠点があります。

それについて考えさせてください。多分私はすぐにこのケースのためのより良い解決策を持っています;)

編集:さて、私は次の解決策を好むでしょう:

template<class derived>
class base
{
    template<std::size_t n> struct test {
        static_assert(n != sizeof(no), "derived doesn't implement used interface method");
    };

protected:
    base() {}

public:
    void bar()
    {        
        static_cast<derived*>(this)->bar();
        test<sizeof(class_helper<derived>::has_implemented(&derived::bar))>();
    }
};

「保護」セクションで基本クラスのデフォルトのコンストラクターを定義する必要があることに注意してください。これを行わないと、メンバー関数を呼び出すと、割り当てられていないメモリにアクセスする可能性があるため、アクセス違反が発生する可能性があります。'base' 型のオブジェクトを宣言するのは安全ではありません。

于 2011-04-19T13:35:52.457 に答える