2017-01-17 9 views
1

次のコードパターンを達成しようとしています。関数がテンプレートクラスメソッドへのポインタ

struct Worker { 
    void update(/* function pointer */) { 

     for(unsigned int i = 0; i < 10; i++) { 
      /* function execution */ 
     } 
    } 
} 

template <typename t_derive> 
struct BaseCrtp { 
    void method1() { 
     static_cast<t_derive*>(this)->method1(); 
    } 

    void method2() { 
     static_cast<t_derive*>(this)->worker.update(/*fptr of Derived1::method2*/); 
    } 
} 

struct Derived1 : public BaseCrtp<Derived1> { 
    Worker worker; 

    void method1() { 
     std::cout << "Derived1::method1" << std::endl; 
    } 

    void method2() { 
     std::cout << "Derived1::method2" << std::endl; 
    } 
} 

私はDeriver1のmethod2をWorker :: updateのインスタンスで呼びたいと思います。更新関数に注入できる関数ポインタを定義するにはどうすればよいですか?

+2

'update'はメンバへのポインタではなくプレーンな関数ポインタを必要としているようです。代わりに 'std :: function'を使うことを考えてください。 – molbdnilo

+2

'method2'は静的メンバー関数ではないので、それを呼び出すために' Derived1'型のオブジェクトを持っている場合にのみ呼び出すことができます。 「労働者」にはそのような議論はない。 molbdniloと言う:あなたはstd :: functionが必要です。 –

答えて

3
struct Worker { 
    void update(/* function pointer */) { 
    ..... 

Worker::updateテンプレートメンバ関数を行います

struct Worker { 
    template<typename Func> 
    void update(Func&& func) { 
    ..... 

またはstd::functionを使用します。

その後
struct Worker { 
    void update(std::function<void()> func) { 
    ..... 

以下のようにあなたのBaseCrtp<>::method2にラムダを経由してコールバックを渡す:

void method2() { 
    static_cast<t_derive*>(this)->worker.update(
     [this]{ static_cast<t_derive*>(this)->method2(); } 
    ); 
} 

全例:hereまたはhere (std::function alternative)見られるように

#include <iostream> 
#include <functional> 

struct Worker { 

    template<typename Func> 
    void update(Func&& func) { 
     for(unsigned int i = 0; i < 10; i++) { 
      func(); 
     } 
    } 

    //alternatively.... 
    // 
    //void update(std::function<void()> func) { 
    // for(unsigned int i = 0; i < 10; i++) { 
    //  func(); 
    // } 
    //} 
}; 

template <typename t_derive> 
struct BaseCrtp { 
    void method1() { 
     static_cast<t_derive*>(this)->method1(); 
    } 

    void method2() { 
     static_cast<t_derive*>(this)->worker.update(
      [this]{ static_cast<t_derive*>(this)->method2(); } 
     ); 
    } 
}; 

struct Derived1 : public BaseCrtp<Derived1> { 
    Worker worker; 

    void method1() { 
     std::cout << "Derived1::method1" << std::endl; 
    } 

    void method2() { 
     std::cout << "Derived1::method2" << std::endl; 
    } 
}; 

template<typename T> 
void process(BaseCrtp<T>& t){ 
    t.method2(); 
} 

int main(){ 
    Derived1 d1; 
    process(d1); 
} 


+0

ありがとう、この作品は完璧に。 – vixiv

1

マーティン・ボナーは、私はあなたが呼び出したいメソッドへのポインタを派生クラスと非型テンプレートパラメータを含む型テンプレートパラメータでワーカーテンプレートを利用することができると思い示唆したように。これは以下のように行うことができます。

template <class T, void (T::*)(void)> 
struct Worker { 
    void update(T *t) { 
     t->method2(); 
    } 
}; 

struct Foo { 
    void method2() { } 
    Worker<Foo, &Foo::method2> worker; 
}; 

int main() { 
    Foo foo; 
    foo.worker.update(&foo); 
} 

[online demo]

をこのコンパイラの最適化を使用した場合、おそらく実際に最初の場所でCRTPを使用する点である今、インライン化する必要があります。

[godbolt]

関連する問題