Переносимость собственных свойств C ++

Попытайтесь использовать dos2unix для снятия изоляции с ^M.

27
задан Marc Mutz - mmutz 7 May 2011 в 21:34
поделиться

2 ответа

Это что-то похожее на то, что вы просите, и (я надеюсь) стандарт C ++ ...

#include <iostream>

template<typename C, typename T, T (C::*getter)(), void (C::*setter)(const T&)>
struct Property
{
    C *instance;

    Property(C *instance)
        : instance(instance)
    {
    }

    operator T () const
    {
        return (instance->*getter)();
    }

    Property& operator=(const T& value)
    {
        (instance->*setter)(value);
        return *this;
    }

    template<typename C2, typename T2,
             T2 (C2::*getter2)(), void (C2::*setter2)(const T2&)>
    Property& operator=(const Property<C2, T2, getter2, setter2>& other)
    {
        return *this = (other.instance->*getter2)();
    }

    Property& operator=(const Property& other)
    {
        return *this = (other.instance->*getter)();
    }
};

//////////////////////////////////////////////////////////////////////////

struct Foo
{
    int x_, y_;

    void setX(const int& x) { x_ = x; std::cout << "x new value is " << x << "\n"; }
    int getX() { std::cout << "reading x_\n"; return x_; }

    void setY(const int& y) { y_ = y; std::cout << "y new value is " << y << "\n"; }
    int getY() { std::cout << "reading y_\n"; return y_; }

    Property<Foo, int, &Foo::getX, &Foo::setX> x;
    Property<Foo, int, &Foo::getY, &Foo::setY> y;

    Foo(int x0, int y0)
        : x_(x0), y_(y0), x(this), y(this)
    {
    }
};

int square(int x)
{
    return x*x;
}

int main(int argc, const char *argv[])
{
    Foo foo(10, 20);
    Foo foo2(100, 200);
    int x = foo.x; std::cout << x << "\n";
    int y = foo.y; std::cout << y << "\n";
    foo.x = 42; std::cout << "assigned!\n";
    x = foo.x; std::cout << x << "\n";
    std::cout << "same instance prop/prop assign!\n";
    foo.x = foo.y;
    std::cout << "different instances prop/prop assign\n";
    foo.x = foo2.x;
    std::cout << "calling a function accepting an int parameter\n";
    std::cout << "square(" << foo.x << ") = " <<  square(foo.x) << "\n";
    return 0;
}

Как вы можете видеть из main, использование прозрачно, если вы присваиваете значения типа T (здесь int) или неявно преобразуются в T для свойств и пока вы преобразовывая их обратно в T значения при чтении.

Поведение будет другим, однако, если вы, например, передадите foo.x шаблонной функции, потому что тип foo.x - это не int, а Property<Foo, int, ...> вместо этого.

У вас также могут быть проблемы с не шаблонными функциями ... вызов функции, принимающей значение T, будет работать нормально, однако параметр T&, например, будет проблемой, потому что в основном функция запрашивает переменная для прямого доступа по адресу. По той же причине вы не можете, конечно, передать адрес свойства функции, принимающей параметр T*.

27
ответ дан 28 November 2019 в 05:30
поделиться

Я ищу портативный и относительно чистый метод объявления синтаксически засахаренных свойств, который будет компилироваться в последних компиляторах для Windows, OSX и Linux.

Вы описываете возможности типа «мета-объект», такие как свойства, определенные во время компиляции или во время выполнения, такие как те, которые могут быть иначе реализованы через «Java-бины» или «.NET отражение», или любое количество способов использования языков сценариев высокого уровня, таких как Python и Perl.

Например, то, что вы описываете (свойства времени компиляции и / или времени выполнения), реализовано в библиотеках Qt (C ++) через QMetaObject. Вы можете создать его экземпляр напрямую, использовать его как «член» в ваших классах или получить из QObject, чтобы «автоматически» получить поведение этого мета-объекта (и некоторые другие вещи, такие как «приведение» помогает, и сигналы / слоты пересекаются -потоки). Конечно, они довольно кроссплатформенные (например, Win, Mac, Posix).

Я не большой поклонник использования __declspec(), за исключением очень специфичного для платформы использования, такого как явный экспорт типов через «Microsoft Extension DLL» (которого я обычно стараюсь избегать, если это возможно). Я не думаю, что есть какой-либо способ сделать такое использование "кросс-платформенным" (поскольку это конкретное использование специфично для библиотек MS DLL).

Точно так же было бы не очень сложно написать собственный класс типа «MyMetaObject», который по сути является «словарем», «хэшем» или «ассоциативным массивом», который используются вашими объектами и который заполняется динамически. во время выполнения, даже с вашими внутренними типами (такими как MyColor, MyTime, MyFilePath и т. д.), я делал это несколько раз, и это не должно быть много работы, и это может работать довольно элегантно. (QMetaObject, как правило, немного более мощный, чем эти простые подходы, но он требует этапа компиляции «moc», который является очень мощным шагом для генерации кода быстрого поиска для его свойств и включения сигналов / слотов ).

Наконец, вы начинаете слегка касаться домена «Динамический C ++», что подразумевает более легкое, почти скриптовое использование синтаксиса C ++. Вот одно предложение, которое углубляется в это динамическое использование, где вы пишете сценарий с этими свойствами, не требуя повторной компиляции. (Это конкретное предложение основано на поведении типа QMetaObject, но есть и другие предложения с похожими соображениями об использовании):

http://www.codeproject.com/KB/cpp/ dynamic_cpp.aspx

Если вы используете Google «Dynamic C ++» или «C ++ Scripting», у вас может появиться еще несколько идей. В некоторых из этих вещей есть злобные умные мысли.

3
ответ дан 28 November 2019 в 05:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: