2017-01-11 9 views
2

私は、静的関数を作成するアクセサテンプレートクラスの1つのコンポーネントであるC++のプロパティライクなシステムで作業しています。オーバーロードされたテンプレートクラス

template <typename T, typename V, V (T::*getf)(), void (T::*setf)(V)> 
struct Accessor 
{ 
    static V Get(T* obj) 
    { 
     return (obj->*getf)(); 
    } 

    static void Set(T* obj, V aValue) 
    { 
     return (obj->*setf)(aValue); 
    } 
}; 

そして、私は上のアクセサを使用することがありますテストクラス:ここ

は、アクセサは次のようになります。 SetFooがintを取る方法に注意してください。SetBarはconst int &をとります。

class TargetClass 
{ 
    int foo; 
    int bar; 

public: 
    TargetClass(int f, int b) 
     : foo(f) 
     , bar(b) 
    { 
    } 

    int GetFoo() 
    { 
     return foo; 
    } 

    void SetFoo(int f) 
    { 
     foo = f; 
    } 

    int GetBar() 
    { 
     return bar; 
    } 

    void SetBar(const int& b) 
    { 
     bar = b; 
    } 
}; 

そして最後に、ここでの用法です:

int main() 
{ 
    TargetClass* target = new TargetClass(5, 3); 

    // Works great 
    typedef Accessor<TargetClass, int, &TargetClass::GetFoo, &TargetClass::SetFoo> fooAcessor; 
    fooAcessor::Set(target, 13); 
    int foo = fooAcessor::Get(target); 

    // Doesn't work, because TargetClass::SetBar takes a const int& as an argument, instead of an int 
    typedef Accessor<TargetClass, int, &TargetClass::GetBar, &TargetClass::SetBar> barAcessor; 

    delete target; 
    return 0; 
} 

私はそれが第四引数ですのでAcessor構造体を「オーバーロードする」試みたがconstのV &ですが、それが動作するようには思えません。私がここでやろうとしていることは可能ですか?

+0

set関数に 'const int&'を一貫して使用しないのはなぜですか?それでは 'void SetFoo(int f)'と 'template 'に変更します。 – wally

+0

私はアクセサーを可能な限り柔軟にしようとしています。実際には、プリミティブ型だけでなく、クラス/構造体、ポインタとともに使用されます。残念ながら、コードベース全体にすべてのセッターでconst参照を使用させるのは現実的ではありません。/ –

答えて

1

をお持ちの場合C++へのアクセス17、そしてその間に提案された標準が変更されないと仮定すると、typ自動的に推定されます:

template <typename F> 
struct get_types; 

template <typename T, typename V, typename... VP> 
struct get_types<V(T::*)(VP...)> 
{ 
    using return_type = V; 
    using class_type = T; 
}; 

template <auto getf, auto setf> 
struct Accessor { 
    using V = typename get_types<decltype(getf)>::return_type; 
    using T = typename get_types<decltype(getf)>::class_type; 
    static V Get(T* obj) 
    { 
     return (obj->*getf)(); 
    } 

    static void Set(T* obj, V aValue) 
    { 
     return (obj->*setf)(aValue); 
    } 
}; 

class TargetClass { 
    int foo; 
    int bar; 
public: 
    TargetClass(int f, int b) 
     : foo(f) 
     , bar(b) {} 
    int GetFoo() { return foo; } 
    void SetFoo(int f) { foo = f; } 
    int GetBar() { return bar; } 
    void SetBar(const int& b) { bar = b; } 
}; 

int main() 
{ 
    TargetClass* target = new TargetClass(5, 3); 
    using fooAccessor = Accessor<&TargetClass::GetFoo, &TargetClass::SetFoo>; 

    fooAccessor::Set(target, 13); 
    int foo = fooAccessor::Get(target); 

    using barAcessor = Accessor<&TargetClass::GetBar, &TargetClass::SetBar>; 
    barAcessor::Set(target, 13); 
    int bar = barAcessor::Get(target); 

    delete target; 
    return foo + bar; 
} 

この時点では、プログラムはcompiles on gcc 7 (snapshot)です。

+0

私は現在C++ 17にアクセスできないが、これは将来、いつかサポートされることを知っておいてよかった! (私は以前テンプレートパラメータでautoを試していましたが、コンパイラはそれが許可されていないと言っていました)。 –

+0

また、getとset関数からクラスと戻り値の型を取得する素晴らしいトリック! –

1

あなたは、設定された関数のパラメータに別のテンプレートパラメータを追加することができます。その後、

template <typename T, typename V, typename VP, V(T::*getf)(), void (T::*setf)(VP)> 

そして、両方のケースのために使用します。

typedef Accessor<TargetClass, int, int, 
    &TargetClass::GetFoo, &TargetClass::SetFoo> fooAcessor; 

typedef Accessor<TargetClass, int, const int&, 
    &TargetClass::GetBar, &TargetClass::SetBar> barAcessor; 

全プログラム:

template <typename T, typename V, typename VP, V(T::*getf)(), void (T::*setf)(VP)> 
struct Accessor 
{ 
    static V Get(T* obj) 
    { 
     return (obj->*getf)(); 
    } 

    static void Set(T* obj, V aValue) 
    { 
     return (obj->*setf)(aValue); 
    } 
}; 

class TargetClass 
{ 
    int foo; 
    int bar; 

public: 
    TargetClass(int f, int b) 
     : foo(f) 
     , bar(b) 
    { 
    } 

    int GetFoo() 
    { 
     return foo; 
    } 

    void SetFoo(int f) 
    { 
     foo = f; 
    } 

    int GetBar() 
    { 
     return bar; 
    } 

    void SetBar(const int& b) 
    { 
     bar = b; 
    } 
}; 

int main() 
{ 
    TargetClass* target = new TargetClass(5, 3); 

    // now has extra int parameter 
    typedef Accessor<TargetClass, int, int, &TargetClass::GetFoo, &TargetClass::SetFoo> fooAcessor; 
    fooAcessor::Set(target, 13); 
    int foo = fooAcessor::Get(target); 

    // Works now, because TargetClass::SetBar's function parameter was specified explicitly as const int& 
    typedef Accessor<TargetClass, int, const int&, &TargetClass::GetBar, &TargetClass::SetBar> barAcessor; 
    barAcessor::Set(target, 13); 
    int bar = barAcessor::Get(target); 

    delete target; 
    return 0; 
} 
+0

自動的に推論させる方法があることを期待していました。 –

+0

@ M.Palko [こちら](http://stackoverflow.com/a/41599305/1460794)を参照してください。 – wally

関連する問題