Как сделать «вычисляемый атрибут» для класса C ++, используя шаблоны - PullRequest
2 голосов
/ 13 августа 2010

Я пытаюсь реализовать универсальный метод для помещения в класс вычисляемого значения в качестве значения памяти только для чтения.

Я успешно выполнил его, используя следующий макрос:

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

генерирует следующий рабочий код (используя 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;}
};

Дело в том, что я могу использовать класс таким образом:

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 <br> error: template argument 3 is invalid

в строке, где создается экземпляр класса шаблона.

Не могли бы вы мне помочь?

Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 13 августа 2010

потому что 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;
};

Редактировать: Спасибоto Georg Fritzsche , согласно его комментарию, последний параметр шаблона должен принимать const функцию-член, а _instance.*F() нужны скобки :) (о! я их забыл!)

1 голос
/ 13 августа 2010

Как насчет этого:

#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;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...