6

CRTP 基本クラスのメンバー関数の指定された後期リターンで decltype を使用しようとしていますが、次のエラーが発生していますinvalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >

template<class Op>
struct Operation
{
    template<class Foo>
    auto operator()(const Foo &foo) const ->
        typename std::enable_if<is_foo<Foo>::value,
                                decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type     
    {
        return static_cast<const Op*>(this)->call_with_foo(foo);
    }
};


template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
    explicit AnyOp(Functor func) : func_(func) {}

    template<class Foo>
    bool call_with_foo(const Foo &foo) const
    {
        //do whatever
    }

  private:
    Functor func_;
};

私は基本的に、すべての sfinae ボイラー プレートを基本クラスに移動しようとしているので、作成する操作ごとに繰り返す必要はありません (現在、各操作には 6 つの異なる呼び出しがあり、約 50 の操作があるため、かなりの量がありますenable_if を何度も繰り返します)。

オーバーロードに依存するソリューションを試しましたが、渡される可能性のある型の 1 つは、std にバインドされた呼び出し可能なもの (これは C++03 または C++0x ラムダの通常のファンクターである可能性があります) です。 :function 残念ながら、std::function からのオーバーヘッドは、ごくわずかですが、実際にはこのアプリケーションに違いをもたらします。

現在持っているものを修正する方法はありますか、またはこの問題を解決するためのより良い解決策はありますか?

ありがとう。

4

2 に答える 2

7

別の回答がすでに説明しているように、クラスの基本クラスのいずれかでクラスのメンバーにアクセスしようとしています。その時点ではメンバーがまだ宣言されていないため、これは失敗します。

基本クラスをインスタンス化すると、すべてのメンバー宣言がインスタンス化されるため、戻り値の型を知る必要があります。戻り値の型を に依存させることができます。これにより、戻り値の型が判明するFooまで計算を遅らせることができFooます。これにより、基本クラスが次のように変更されます

// ignore<T, U> == identity<T>
template<typename T, typename Ignore> 
struct ignore { typedef T type; };

template<class Op>
struct Operation
{
    template<class Foo>
    auto operator()(const Foo &foo) const ->
        typename std::enable_if<is_foo<Foo>::value,
           decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type     
    {
        return static_cast<const Op*>(this)->call_with_foo(foo);
    }
};

これは人為的static_castに に依存する型にキャストするため、Fooすぐに完全な型を必要としませんOpoperator()むしろ、それぞれのテンプレート引数で がインスタンス化されるときに型が完全である必要があります。

于 2011-02-21T01:35:19.943 に答える
1

独自の基本クラスの1つからクラスのメンバーを参照しようとしていますが、クラスの本体がその基本クラス内に存在しないため、失敗します。の戻り型をcall_with_fooメタ関数として計算するためのロジックを基本クラスに渡すことができますか?そのロジックは複雑になることはありますか?

別のオプションは、クラス階層を変更する際の柔軟性に応じて(そして、テンプレートtypedefがあることを忘れないでください)、ラッパーに実装クラスから継承させることです。その逆ではありません。たとえば、AddParensWrapper<T>から継承しT、にoperator()転送するを書くことができますT::call_with_foo。これで依存関係の問題が修正されます。

于 2011-02-20T23:19:11.220 に答える