1

次の関数を書きました。

template< class C, typename T, typename U >
void addVarCB(C * _this, const std::string &name, 
    T(C::*getter)(void) const, U(C::*setter)(const T&), const std::string &def);

次に、セッターが T を入力として受け取ると機能しないことに気付いたので、関数をオーバーロードしました。

template< class C, typename T, typename U >
void addVarCB(C * _this, const std::string &name, 
T(C::*getter)(void) const, U(C::*setter)(T), const std::string &def = "");

そして今、ゲッターが返されるとこれでも失敗することに気づきました

const T &
T &
const T *
T *
const T // yeah this is dumb but someone on my team wrote code like this...

同じコードをあちこちにコピーする運命にあるのでしょうか? うまくいけば、少なくとも参照バージョンだけの解決策はありますか?

この関数は、オブジェクトへの this ポインター、getter および setter パブリック メンバー関数を受け取ることに注意してください。この関数は、後で getter と setter を呼び出すことができる GUI と連動します。

4

2 に答える 2

2

いくつかのテンプレート メタプログラミングで問題を解決できます: (以下では C++11 が必要ですが、boost を使用しても同じことが実現できます)

#include<string>
#include<type_traits>

template<typename T>
struct BaseType {
    typedef typename std::remove_const<typename std::remove_reference<T>::type>::type type;
};

struct MyClass{
    int a;
    std::string s;
    const int & getA() const {return a;}
    void setA(int a) {this->a=a;}
    std::string getS() const {return s;}
};


template< class C, typename Tget, typename Tset, typename U, 
    class = typename std::enable_if<
                std::is_same<
                   typename BaseType<Tget>::type, 
                   typename BaseType<Tset>::type>::value,void>::type >
void addVarCB(C * _this, const std::string &name, 
    Tget(C::*getter)(void) const, U(C::*setter)(Tset), const std::string &def = "") {
}

int main() {
    MyClass c;
    addVarCB(&c,std::string("a"),&MyClass::getA,&MyClass::setA,std::string("a"));
    //addVarCB(&c,std::string("a"),&MyClass::getS,&MyClass::setA,std::string("a")); // Compiler error
}

ここでは、get 型と set 型 (TgetおよびTsetそれぞれ) を個別に推定できるようにします。次に、これらの型から定数または参照を取り除き、それらが同じかどうかを確認します。そうでない場合は、 を使用して特殊化の失敗をトリガーしenable_ifます。

于 2012-10-02T18:41:36.483 に答える
1

GetType独立したテンプレート パラメーターを作成するだけSetTypeで、それらが変換可能かどうかをコンパイラーに心配させることができます。

例えば。これ:

template< class C, typename T, typename U >
void addVarCB(C * _this, const std::string &name, 
    T(C::*getter)(void) const, U(C::*setter)(const T&), const std::string &def);

setterの引数は、返されるものへの const 参照である必要がありgetterます。ただし、これは次のとおりです。

template <typename Class, typename GetResult, typename SetArg, typename SetResult>
void addVarCB(Class *instance, std::string const& name,
              GetResult (Class::*getter)() const,
              SetResult (Class::*setter)(SetArg),
              std::string const &def);

setter引数とgetter戻り値の型が異なることを許可します。ここで、一方を他方に渡したいと仮定すると、それらが変換可能である場合にのみコンパイルされます (または、C++11 または Boost.TypeTraitsis_convertibleを使用してこれを明示的にアサートできます)。


...それがうまくいかないaddVarCB場合は、 の中身を示したり、達成しようとしていることを説明したりすると、おそらく役立つでしょう。

于 2012-10-02T18:22:02.130 に答える