2013-04-18 55 views
2

我正在C++中使用屬性系統(C++ 11也可以),以便類可以將數據提供給腳本系統。我想提供各種屬性的「類型」,最簡單的一個控股公司價值的內部,像這樣:混合參數類型的模板重載

// Simple Property 
template<typename Value> 
class Property { 
    public: 

     Value get() const; 

     void set(Value value); 

    private: 

     Value m_value; 
} 

在大多數情況下,這是確定的,但有時,計算值或有被外界其他原因屬性對象。對於這樣的情況,我想提供這樣一個模板:

// Complicated Property 
template< 
    typename Value, 
    typename ValueOwner, 
    Value (ValueOwner::*Getter)(void) const, 
    void (ValueOwner::*Setter)(Value) 
> 
class Property { 
    // Stuff for calling the getter & setter 
} 

有沒有什麼辦法可以讓這兩個模板,但不重命名其中的一個共存?我想這特殊化的getter/setter模板:

// Complicated Property 
// ... 

// Simple Property 
template<typename Value> 
class Property<Value, void, nullptr, nullptr>; 

但是編譯器不一樣,並抱怨creating pointer to member function non-class type "const void"。 Duh,當然void沒有成員函數。

然後我試圖聲明有足夠的參數模板,然後專門上面的模板,像這樣:

template<typename A, typename B, typename C, typename D> 
class Property; 

// Simple Property 
// ... 

// Complicated Property 
// ... 

但是,這並不能工作,因爲的getter/setter模板不指望typename作爲第三和第四個參數,但指向成員函數。

下一個嘗試:

// Complicated Property 
// ... 

// Simple Property 
template<typename Value> 
class Property< 
    Value, 
    Property<Value>, 
    &Property<Value>::get, 
    &Property<Value>::set 
>; 

未能編譯因爲編譯器現在不模板參數內Property<Value>模板。

好吧,也許這一個:

// Complicated Property 
// ... 

template<typename Value> 
struct PropertyDummy { 
    Value get() const; 
    void set(Value); 
} 

// Simple Property 
template<typename Value> 
class Property< 
    Value, 
    PropertyDummy<Value>, 
    &PropertyDummy<Value>::get, 
    &PropertyDummy<Value>::set 
>; 

這對於getter和setter模板參數產生template argument involves template parameter(s)。當然他們會。

無論如何,將模板重命名爲PropertySimpleProperty這樣的模板對我來說已經足夠好了。但我很好奇,如果有解決方案,以便我可以寫兩個

Property<int> simpleProperty; 

Property<int, MyClass, &MyClass::get, &MyClass::set> complicatedProperty; 

並讓編譯器找出我指的是哪個模板。

回答

3

不過我很好奇,如果有一個解決方案,以便

是的,有

您可以使用以下方法。首先,在某些命名空間中的虛擬類模板客戶端不應與應對:

namespace detail 
{ 
    template<typename T> 
    struct dummy 
    { 
     T get() const { return T(); } 
     void set(T) { } 
    }; 
} 

然後,定義了以下主要的模板:

#include <type_traits> 

// Simple Property 
template<typename Value, 
     typename ValueOwner = detail::dummy<Value>, 
     Value (ValueOwner::*Getter)(void) const = &ValueOwner::get, 
     void (ValueOwner::*Setter)(Value) = &ValueOwner::set, 
     bool = std::is_same<ValueOwner, detail::dummy<Value>>::value 
     > 
class Property { 
    public: 
     Value get() const; 
     void set(Value value); 
    private: 
     Value m_value; 
}; 

上一個虛擬模板參數的值將取決於是否作爲第二個參數傳遞dummy<Value>(當然,客戶端不應該使用dummy類模板)。

然後,你可以專注您的模板的情況下,當最後一個參數是false(這意味着一些參數是爲第二個模板參數提供):

// Complicated Property 
template< 
    typename Value, 
    typename ValueOwner, 
    Value (ValueOwner::*Getter)(void) const, 
    void (ValueOwner::*Setter)(Value) 
> 
class Property<Value, ValueOwner, Getter, Setter, false> 
{ 
    // Stuff for calling the getter & setter 
}; 

最後,你可以使用有兩個聲明你提議:

struct MyClass 
{ 
    int get() const { return 42; } 
    void set(int) { } 
}; 

int main() 
{ 
    Property<int> simpleProperty; 
    Property<int, MyClass, &MyClass::get, &MyClass::set> complicatedProperty; 
} 

這是live compiling example

3

是否需要在編譯時指定getters和setters?您可以使用ValueValueOwner模板參數剛拿到類型:

template< 
    typename Value, 
    typename ValueOwner, 
> 
class Property { 
public: 
    typedef Value (ValueOwner::*Getter)(void) const; 
    typedef void (ValueOwner::*Setter)(Value); 

    Property(Getter getter, Setter setter) 
     : getter(getter), setter(setter) {} 

    // ... 

private: 
    Getter getter; 
    Setter setter; 
}; 

然後相應的函數指針傳遞給構造函數:

Property<int, MyClass> complicatedProperty(&MyClass::get, &MyClass::set); 
+0

那麼,他們不*在編譯時指定*,但它可以很好地利用內聯。我將不得不測試gcc是否足夠聰明,可以將您的解決方案與這些調用聯繫起來。無論如何,謝謝! –