2017-02-09 37 views
0

の種類は以下の、最小限の例を考えてみましょう:型消去およびテンプレートメソッドパターン

struct S { 
    using func_t = void(*)(void *); 

    template<typename T> 
    static void proto(void *ptr) { 
     static_cast<T*>(ptr)->f(); 
    } 

    func_t func; 
    void *ptr; 
}; 

struct T { 
    void f() {} 
}; 

void g(S &s) { 
    s.func(s.ptr); 
} 

int main() { 
    T t; 
    S s; 
    s.func = &S::proto<T>; 
    s.ptr = &t; 
    g(s); 
} 

かなり明白なアイデアは、それが可能なだけでなく、オブジェクト(のようなTの束のタイプを消去することです型)を使用してSのインスタンスの配列を作成し、その配列を反復処理して、所定のメンバ関数を呼び出します。

これまでのところ非常に優れているため、実装が簡単で動作します。

template<typename T, typename F> 
static void proto(void *ptr, F &&f) { 
    auto *t = static_cast<T*>(ptr); 
    std::forward<F>(f)(*t); 
    t->f(); 
} 

またはこの:

template<typename T> 
static void proto(void *ptr, void(*f)(T &)) { 
    auto *t = static_cast<T*>(ptr); 
    f(*t); 
    t->f(); 
} 

は次のように呼び出される:


今私は、消去対象に呼び出される外部関数を提供するために、このようなものだ何かをしたいと思います
s.func(s.ptr, [](auto obj){ /* ... */ }); 

派生クラスの代わりに呼び出し元によって追加の機能が提供される一種のテンプレートメソッドパターン。
私は、特殊化を均等にして関数ポインタに割り当てることができないため、残念ながらそれはできません。

私が見ることができる唯一の選択肢は、以下のいずれかのようにカスタムクラスを定義することです:

何とか f派遣右のメンバ関数への内部呼び出しは、その後、としてそれを使用
struct C { 
    template<typename T> 
    void f(T &t) { /* ... */ } 

    // ... 
}; 

struct S { 
    using func_t = void(*)(void *, C &); 

    template<typename T> 
    static void proto(void *ptr, C &c) { 
     auto t = static_cast<T*>(ptr); 
     c.f(*t); 
     t->f(); 
    } 

    func_t func; 
    void *ptr; 
}; 

これは、ラムダを使用することによって、それほど遠くはありませんが、より冗長で、明示的にクラスを宣言する必要があります。C

これを実現する他の有効な方法はありますか、これが唯一実行可能な解決策ですか?

+0

私は[XY問題](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)を感じます。サポートしているテンプレートマジックが完璧に動作していると仮定して記述したいコードを教えてください。 – nwp

+0

@nwp私は何か似たものを与えました。想像してみれば、私は 's.ptunc(s.ptr、[](auto obj){/ * ... * /});'を呼び出すことを繰り返しています。わずかに異なるラムダを持つ時間。詳細を教えてもらえますか?私はそれをどのように説明するか分からない_より。ごめんなさい。 – skypjack

+0

配列内のすべての要素の共通点は何ですか?彼らは単に共通のメンバ関数 'void f()'を持っていますか? – nwp

答えて

0

あなたは、あなたがこれを行うことができますサポートしたい種類を列挙することができますと仮定すると:それはまともな呼び出し構文を持つ

#include <iostream> 
#include <string> 
#include <vector> 

template <class... Ts> 
struct PseudoFunction { 
    private: 
    template <class T> 
    static void (*function)(T &); 

    template <class T> 
    static void call_func(void *object) { 
     return function<T>(*static_cast<T *>(object)); 
    } 

    template <class Fun> 
    static void assign(Fun) {} 

    template <class Fun, class Head, class... Tail> 
    static void assign(Fun fun) { 
     function<Head> = fun; 
     assign<Fun, Tail...>(fun); 
    } 

    public: 
    template <class T> 
    PseudoFunction(T *t) 
     : object(t) 
     , func(call_func<T>) {} 

    template <class F> 
    static void set_function(F f) { 
     assign<F, Ts...>(f); 
    } 
    void operator()() { 
     func(object); 
    } 

    private: 
    void *object; 
    void (*func)(void *); 
}; 

template <class... Ts> 
template <class T> 
void (*PseudoFunction<Ts...>::function)(T &) = nullptr; 

//example types that are not related and not copy constructible 
//but have the same member function name and signature 
struct T1 { 
    T1() = default; 
    T1(const T1 &) = delete; 
    void func(double d) { 
     std::cout << "T1: " + std::to_string(d) + '\n'; 
    } 
}; 

struct T2 { 
    T2() = default; 
    T2(const T2 &) = delete; 
    void func(double d) { 
     std::cout << "T2: " + std::to_string(d) + '\n'; 
    } 
}; 

int main() { 
    T1 t1; 
    T2 t2; 

    using PF = PseudoFunction<T1, T2>; 

    std::vector<PF> funcs; 
    funcs.push_back(&t1); 
    funcs.push_back(&t2); 

    PF::set_function([](auto &object) { object.func(3.14); }); 
    for (auto &f : funcs) { 
     f(); 
    } 
} 

demo

を(あなたが呼び出す前に関数を指定する必要がちょうどあること潜在的に使用されていない関数ポインタを設定するオーバーヘッドがあります。

おそらくset_functionを実行し、PFを繰り返し処理するラッパーを作成する可能性があります。

関連する問題