2010-08-13 77 views
2

我試圖實現通用方法,將類的計算值作爲只讀的memver值放入類中。如何使用模板爲C++類創建「計算屬性」

我successfuly acomplished它使用下面的宏:

#define READONLY_PROPERTY(datatype, containerclass, access, name)\ 
    class name ## _ ## datatype ## _ROP {\ 
public:\ 
    name ## _ ## datatype ## _ROP(containerclass &c_): cclass(c_) {}\ 
     operator datatype() const {return cclass.access();}\ 
private:\ 
    containerclass &cclass;\ 
}name;\ 
friend class name ## _ ## datatype ## _ROP 

,在該類中使用:

class TestClass { 
public: 
    TestClass(): x(0), y(0), pixels(*this) {} 
    TestClass(int x_, int y_): x(x_), y(y_), pixels(*this) {} 
    int x; 
    int y; 
    READONLY_PROPERTY(int, TestClass, getPix, pixels); 
private: 
    int getPix() {return x * y;} 
}; 

生成以下工作的代碼(使用克++):

class TestClass { 
public: 
    TestClass(): x(0), y(0), pixels(*this) {} 
    TestClass(int x_, int y_): x(x_), y(y_), pixels(*this) {} 
    int x; 
    int y; 
    class pixels_int_ROP { 
    public: 
     class pixels_int_ROP(TestClass &c_): cclass(C_) {} 
     operator int() const {return cclass.getPix();} 
    private: 
     TestClass &cclass; 
    } pixels; 
    friend class pixels_int_ROP; 
private: 
    int getPix() {return x * y;} 
}; 

重點是我可以用這種方式使用這個類:

TestClass tc(10,10); 
std::cout << tc.pixels << std::endl; 

現在,我試圖做同樣的事情在一個以上的C++使用方法模板:

template<class T, class U, U (T::*F)()>; 
class ReadOnlyProperty { 
public: 
    ReadOnlyProperty(T const& instance): _instance(instance) {} 
    operator U const &() const {return _instance.*F();} 
private: 
    T& _instance; 
}; 

class TestClass { 
public: 
    TestClass(): x(0), y(0), pixels(*this) {} 
    TestClass(int x_, int y_): x(x_), y(y_), pixels(*this) {} 
    int x; 
    int y; 
    ReadOnlyProperty<TestClass, int, &TestClass::getPix&> pixels; 
private: 
    int getPix() {return x * y;} 
}; 

但是編譯器說:

error: incomplete type ‘TestClass’ used in nested name specifier
error: template argument 3 is invalid

在所在行的模板類被實例化。

你能幫我嗎?

在此先感謝。

+4

如果一個簡單的成員函數完成這項工作,爲什麼還要經歷所有這些麻煩? 'int TestClass :: pixels()const {return x * y; }',然後'std :: cout << tc.pixels()<< std :: endl;'並完成。 – 2010-08-13 19:19:06

+0

因爲我只是想學習一些關於C++模板的主題,而且我喜歡隱藏如果計算或存儲屬性(以類使用的觀點)的習語。這可能是因爲我現在更多的是一個Python程序員而不是C++程序員,而我習慣於pyhton屬性概念。 – Patxitron 2010-08-13 19:52:26

+0

在C++屬性中,通常通過成員函數(即訪問器)來訪問屬性,對於只攜帶數據的*「small」*結構的成員(例如'struct Point {int x,y;};'),有一些例外。 – 2010-08-13 20:08:11

回答

4

因爲getPix()在用作模板參數時未聲明,並且_instance必須爲const,因爲ReadOnlyProperty構造函數參數爲const

template< class T, class U, U (T::*F)() const > 
class ReadOnlyProperty { 
public: 
    ReadOnlyProperty(T const& instance): _instance(instance) {} 
    operator U const &() const {return (_instance.*F)();} 
private: 
    const T& _instance; 
}; 

class TestClass { 
public: 
    TestClass(): x(0), y(0), pixels(*this) {} 
    TestClass(int x_, int y_): x(x_), y(y_), pixels(*this) {} 
    int x; 
    int y; 
private: 
    int getPix() const {return x * y;} 
public: 
    ReadOnlyProperty<TestClass, int, &TestClass::getPix> pixels; 
}; 

編輯:感謝喬治Fritzsche也,根據他的意見,最後一個模板參數應採取const成員函數和_instance.*F()需求括號:)(哦,我忘了他們!)

+1

如果它在'const'實例上調用它,它應該使用'const'成員函數'U(T :: * F)()const'。它也應該是'(_instance。* F)()' - 函數調用'()'具有比'。*'更高的優先級。 – 2010-08-13 19:29:27

+0

@Georg Fritzsche:是的,它應該是const,我只是清除了它的錯誤:)感謝您的關注,我更改了最後一個_template parameter_以獲取'const'成員函數。 – 2010-08-13 19:48:54

+0

謝謝你們倆。答案和評論已經解決了我的問題。 – Patxitron 2010-08-13 19:54:14

1

如何這一點:

#include <functional> 

template<class R, class UA, class P> 
class MyBind 
{ 
    public: 
     MyBind(UA unaryAction, P param) 
      :_unaryAction(unaryAction) 
      ,_parameter(param) 
     {} 
     operator R const&() const 
     { 
      return _action(_parameter); 
     } 
    private: 
     UA _unaryAction; 
     P& _parameter; 
}; 

然後,它可以像這樣使用:

class TestClass 
{ 
     typedef std::const_mem_fun_t<int, TestClass> MethodCall; 
     int getPix() const 
     { 
      return x * y; 
     } 
    public: 
     TestClass(int x_, int y_) 
      :x(x_) 
      ,y(y_) 
      ,pixels(std::mem_fun(&TestClass::getPix), *this) 
     {} 
     int  x; 
     int  y; 
     MyBind<int, MethodCall, TestClass>  pixels; 
};