tags:

views:

106

answers:

2

I'm trying to implement generic method to put in a class a calculated value as a read-only memver value.

I've successfuly acomplished it using the following macro:

#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

that used in this class:

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;}
};

generates the following working code (using g++):

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;}
};

The point is that I can then use the class this way:

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

Now I'm trying to do the same thing in a more C++ way using templates:

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;}
};

but the compiler says:

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

in the line where the template class is instantiated.

Could you, please, help me?

Thanks in advance.

+4  A: 

because getPix() was not declared when it is used as a template parameter, and _instance have to be const because ReadOnlyProperty constructor parameter is 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;
};

Edit: Thanks to Georg Fritzsche, According to his comment, the last template parameter should take a const member function and _instance.*F() needs parentheses :) (oh! i forgot them!)

PC2st
It should take a `const` member function, `U (T::*F)() const`, if its calling it on a `const` instance. It should also be `(_instance.*F)()` - the function call `()` has higher precedence than `.*`.
Georg Fritzsche
@Georg Fritzsche: Yes, it should be const and i just had cleaned its errors :) thanks for your attention, i changed the last _template parameter_ to take `const` member functions.
PC2st
Thank you both. The answer and the comment have been resolved my question.
Patxitron
+1  A: 

How about this:

#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;
};

Then it can be used like this:

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;
};
Martin York