почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
разве не лучше писать Core->SystemA->Manager->Call();
чем GetCore()->GetSystemA()->GetManager()->Call();
?
или еще хуже с разными с порнонотациями типа :
getCore()->getSystemA()->getManager()->Call();
или полные дрова:
get_Core()->get_SystemA()->get_Manager()->Call();
я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
(костыли и мс-специфичные прагмы не предлагать, пробовал уже)
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали:
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
Фигасе.
Я, проектируя класс, сразу закладываюсь на то, что его будет использовать полный баран и гадить везде, где только можно (даже если это мой собственный проект).
А ты молодец, я погляжу
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
Потому, что они НЕ НУЖНЫ.
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call();
Оба хуже.
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
Просто некоторые люди неправильно понимают идею изоляции. Ничего плохого в открытой переменной нет. С точки зрения инкапсуляции вариант
public: Type a;
НИЧЕМ не отличается от
public:
Type getA() {return a;}
void setA(const Type& a_) { a = a_;}
private:
A a;
Но первый вариант нагляден, прост, поддерживает любую семантику, которая определена для Type (например, попробуй во втором варианте вызвать над а инкремент) и позволяет компилятору оптимизировать оптимизируемое.
У второго варианта никаих достоинств, одни недостатки.
Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
K>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
Вот потому.
Здравствуйте, Vamp, Вы писали:
V>Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>Здравствуйте, Vamp, Вы писали:
V>>Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Ops>Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет.
эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов.
Так что делать код нечитаемым ради мифических ништяков смысла я лично не вижу, а те полраза, когда это вдруг понадобится, меня не напряжет пройтись по местам использования и преобразовать прямой доступ в методы.
Тем более что сайд-эффекты сами по себе возникают редко, обычно они являются частью какой-то более сложной функциональности, достойной внятного именования, и "пропертя" опять же оказываются не у дел.
Ops>Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет.
Нет. По двум причинам.
Во-первых, переменная — либо внутреннее дело класса, либо внешнее. Если она внешнее — например, это элемент массива, в классе, инкапсулирующем массив — то уведомлять никого ни о чем не надо.
Если эта переменная внутренняя — как, например, в том же классе размер массива — то наружу от нее вообще ничего не торчит, а вместо этого есть метод-глагол resize, и, так уж и быть, рид-аксессор length(). Кстати, я просто забыл про такие случаи в своем посте выше, "полузакрытым" переменным, запись в которые происходит "глаголом", а чтение доступно свободно, разрешается иметь рид-аксессор.
Во-вторых, я в своей жизни повидал аксессоров (и нахлебался с ними) — и ни разу еще не видел, чтобы они реализовывали эти самые "сайд-эффекты". Тупое присваивание.
J>эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов.
Я надеялся на твою поддержку!
J>Так что делать код нечитаемым ради мифических ништяков смысла я лично не вижу,
Да не только нечитаемым! Это половина синтаксиса сразу коту под хвост. Ни инкремента, ни декремента, ни += (и все остальные *=), ни экстракции из потока, ни сдвигов, НИЧЕГО!
А вместо
А = B + C;
изволь писать
setA(getB() + getC());
И все только потому, что кто-то когда-то придумал понятие propery для Delphi — потому что так удобно было организовывать визуальное программирование!
Здравствуйте, Kingofastellarwar, Вы писали:
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call(); K>? K>или еще хуже с разными с порнонотациями типа : K>getCore()->getSystemA()->getManager()->Call(); K>или полные дрова: K>get_Core()->get_SystemA()->get_Manager()->Call();
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
K>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
K>(костыли и мс-специфичные прагмы не предлагать, пробовал уже)
Один вопрос. Зачем?!
Здравствуйте, Vamp, Вы писали:
V>Если эта переменная внутренняя — как, например, в том же классе размер массива — то наружу от нее вообще ничего не торчит, а вместо этого есть метод-глагол resize, и, так уж и быть, рид-аксессор length(). Кстати, я просто забыл про такие случаи в своем посте выше, "полузакрытым" переменным, запись в которые происходит "глаголом", а чтение доступно свободно, разрешается иметь рид-аксессор.
Отчасти это стилистический вопрос. Как красивее писать:
length() / resize(n) — разные корни; пример — std::string
size() / resize(n) — существительное и глагол от существительного; пример — std::vector
size() / size(n) — омонимы (существительное и глагол пишутся одинаково); пример: std::stream::rdbuf()
getsize() / setsize(n); getSize() / setSize(n); get_size() / set_size(n) — разные конвенции приставок get- и set-
Ещё бывает пара get/put, а не только get/set.
Проперти, будучи в языке, внесли бы строгость. Но их нет, и они не внесли.
V>Во-вторых, я в своей жизни повидал аксессоров (и нахлебался с ними) — и ни разу еще не видел, чтобы они реализовывали эти самые "сайд-эффекты". Тупое присваивание.
А как именно нахлебался?
Я в одном проекте вполне себе пользовался пропертями и находил их удобными. Сейчас уже всех подробностей не помню, кроме того, что
1) в макросах — не надо писать разные макросы, отдельно для функций, отдельно для переменных
2) нетупое присваивание — валидация; установка обратного указателя
V>>Во-вторых, я в своей жизни повидал аксессоров (и нахлебался с ними) — и ни разу еще не видел, чтобы они реализовывали эти самые "сайд-эффекты". Тупое присваивание.
К>А как именно нахлебался?
Геморрой с изменением:
1. Операторы использовать нельзя (прощайте ++, +=, >> и т.д.).
2. Функции и функции-члены использовать нельзя (прощайте resize(), reserve(), sort() и т.д.).
3. Всегда надо заводить лишний объект.
4. Всё делается только через присваивание этого лишнего объекта, которое крайне редко может сравниться по оптимальности с прямой работой с объектом.
5. Даже в случае тривиальных геттеров-сеттеров компилятор не будет достаточно умным, чтобы переписать код изменения третьего объекта на прямую работу с объектом-членом.
Здравствуйте, Kingofastellarwar, Вы писали:
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call(); K>? K>или еще хуже с разными с порнонотациями типа : K>getCore()->getSystemA()->getManager()->Call(); K>или полные дрова: K>get_Core()->get_SystemA()->get_Manager()->Call();
Всё это туфта. Писать только так:
assert(NULL != GetCoreSystemAManager());
GetCoreSystemAManager()->Call();
А все эти ваши макароны кушайте сами.
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
С-style?
K>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
Проперти не нужны
Здравствуйте, Vamp, Вы писали:
V>А вместо V>А = B + C; V>изволь писать V>setA(getB() + getC());
V>И все только потому, что кто-то когда-то придумал понятие propery для Delphi — потому что так удобно было организовывать визуальное программирование!
Это случилось чуть раньше — в OLE/COM.
Там надо было.
А на них уже соорудили Дельфу.
К>length() / resize(n) — разные корни; пример — std::string К>size() / resize(n) — существительное и глагол от существительного; пример — std::vector
Зависит от. Просто для строки понятие length более применимо (на мой вкус), чем size. А глагола relength нет.
К>size() / size(n) — омонимы (существительное и глагол пишутся одинаково); пример: std::stream::rdbuf()
Size — не глагол. Так что мне не нравится. Впрочем, это не единственная странная вещь в стримах.
К>getsize() / setsize(n); getSize() / setSize(n); get_size() / set_size(n) — разные конвенции приставок get- и set- К>Ещё бывает пара get/put, а не только get/set.
Дело не в том, какая приставка, а в том, что они мешают в целом.
К>Проперти, будучи в языке, внесли бы строгость. Но их нет, и они не внесли.
Я так и не вижу их преимуществ. Все это неизжитый дельфизм.
К>А как именно нахлебался?
Да по-всякому. Я тут уже два раза писал, как половина полезного синтаксиса закрывается. См. выше.
Кроме этого, усложняется косвенная адресация. Например, есть желание универсально обращаться к полю. Если член — открытая переменная, то это делается просто:
Ну и какой код нагляднее? Я уже не говорю, что пока сигнатуру функции правильно напишешь — семь потов сойдет. Особенно если там их несколько в зависимости от константности.
К>2) нетупое присваивание — валидация;
И что ты делал, если валидация обламывалась?
Здравствуйте, Vamp, Вы писали:
K>>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя? V>Потому, что они НЕ НУЖНЫ.
нужны.
кроме написания хорошего кода с нуля, есть еще работа с legacy кодом.
например, имеем код
struct Foo
{
int state;
};
и пару сотен использований токена "state" в исходниках.
VisualAssistX выдает неправильный список использований, или вообще отказывается его выдавать.
надо понять где, как и зачем state меняется, и например добавить туда новый код (в setter)
пишем
struct Foo
{
__declspec(property(get=get_state)) int state;
int m_state;
int get_state() const { return m_state; }
};
компилируем, и в ошибках компиляции видим где state меняется.
если таких мест мало, можно добавить всякие set_default_state(), change_state(x), и т.п.
если изменения получаются очень сложными, в качестве временной меры можно добавить set=set_state, и не трогать существующий код,
позже, после десятка-другого итераций рефакторинга, когда код улушится, можно будет убрать __declspec(property()).
------
Типичный пример добавления кода в сеттер:
было:
struct GodStructure
{
// ...
// очень много полейint state;
};
Здравствуйте, Vamp, Вы писали:
V>Но первый вариант нагляден, прост, поддерживает любую семантику, которая определена для Type (например, попробуй во втором варианте вызвать над а инкремент) и позволяет компилятору оптимизировать оптимизируемое. V>У второго варианта никаих достоинств, одни недостатки.
Инкремент — раскладывается в get(), прибавление 1 и set().
Оптимизация — нет сейчас настолько тупого компилятора в майнстриме, чтобы не смог оптимизировать такой случай, заметив, что get() это чтение значения, а set() — присвоение. Компиляторы справляются и со значительно более сложными случаями.
А вот преимущество пропертей, которое ты не сделаешь никакой заменой на открытый член — это то, что, например, для отладки ты в set() делаешь контроль, кто ставит значение и почему, и компилируешь такой код без проблем, а при открытом члене ты должен расставлять watchpoints или форсировать замену во всём коде прямого присвоения на явный set().
Итого — у первого варианта сплошные недостатки, а у второго (property) — сплошные достоинства.
V>Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Правильно — property как механизм значительно удобнее.
K>>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет? V>Вот потому.
Я использовал properties в Питоне. Очень таки удобно.
Здравствуйте, jazzer, Вы писали:
V>>>Во-вторых, я в своей жизни повидал аксессоров (и нахлебался с ними) — и ни разу еще не видел, чтобы они реализовывали эти самые "сайд-эффекты". Тупое присваивание. К>>А как именно нахлебался? J>Геморрой с изменением: J>1. Операторы использовать нельзя (прощайте ++, +=, >> и т.д.).
Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба.
J>2. Функции и функции-члены использовать нельзя (прощайте resize(), reserve(), sort() и т.д.).
Именно для этого случая их вообще-то и не положено использовать. Хотя, с другой стороны, механизм, позволяющий делать что-то вроде
спокойно бы закрыл эту проблему, позволив определять методы для свойств как алиасы для методов класса-хозяина.
J>3. Всегда надо заводить лишний объект. J>4. Всё делается только через присваивание этого лишнего объекта, которое крайне редко может сравниться по оптимальности с прямой работой с объектом.
Эти пункты являются следствием нерешённости пунктов 1 и 2. Если их решить, этих проблем не будет.
J>5. Даже в случае тривиальных геттеров-сеттеров компилятор не будет достаточно умным, чтобы переписать код изменения третьего объекта на прямую работу с объектом-членом.
Компиляторы сейчас умеют и значительно более умные вещи, а эта будет для них тривиальщиной.
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call(); K>?
Здравствуйте, Kingofastellarwar, Вы писали:
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
Потомучто это удел скриптов
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call(); K>?
Писать несколько гетов в одной строчке? у вас гавно-архитектура, отсюда все эти выдуманые проблемы.
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
Перейди на скрипты, С++ для тебя противопоказан. Даже С для тебя будет противопоказан.
K>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
В 11 стандарте нет концептов, вот это действительно беда — а проперти это паталогия скриптеров
Если по существу, то проектируются всегда от интерфейсов
любое изменение таких данных влечет за собой измененние состояния,
как минимум выставить флаг инвалидации, и в get она проверяется (так называемая линивый пересчет)
например setPosition, getMatrix
setPosition выставит флаг инвалидации
getMatrix пересчитает матрицу только в том случае если данные изменились, в противном вернет as is
Здравствуйте, netch80, Вы писали: N>Здравствуйте, jazzer, Вы писали: V>>>>Во-вторых, я в своей жизни повидал аксессоров (и нахлебался с ними) — и ни разу еще не видел, чтобы они реализовывали эти самые "сайд-эффекты". Тупое присваивание. К>>>А как именно нахлебался? J>>Геморрой с изменением: J>>1. Операторы использовать нельзя (прощайте ++, +=, >> и т.д.). N>Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба.
Ага. Сколько у нас там операторов? С десяток наберется ведь?
И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты. J>>2. Функции и функции-члены использовать нельзя (прощайте resize(), reserve(), sort() и т.д.). N>Именно для этого случая их вообще-то и не положено использовать. Хотя, с другой стороны, механизм, позволяющий делать что-то вроде N>
N>спокойно бы закрыл эту проблему, позволив определять методы для свойств как алиасы для методов класса-хозяина.
Те же проблемы, что и с операторами, только еще хуже. Это ж для всех функций-членов всех классов придется подобное писать, и для каждого свое, так что даже в макрос не упрячешь. А попробуй-ка воспроизведи интерфейс std::string, ага. Лучше сразу застрелиться.
Так что овчинка выделки не стоит совершенно. J>>3. Всегда надо заводить лишний объект. J>>4. Всё делается только через присваивание этого лишнего объекта, которое крайне редко может сравниться по оптимальности с прямой работой с объектом. N>Эти пункты являются следствием нерешённости пунктов 1 и 2. Если их решить, этих проблем не будет.
Одна беда — что их решить вменяемым способом нельзя. А так оно конечно. J>>5. Даже в случае тривиальных геттеров-сеттеров компилятор не будет достаточно умным, чтобы переписать код изменения третьего объекта на прямую работу с объектом-членом. N>Компиляторы сейчас умеют и значительно более умные вещи, а эта будет для них тривиальщиной.
Доверяй, но проверяй.
На сцене компилятор GCC4.4.4 (нынешний стандартный RedHat-овский), с оптимизацией -О3 (в продакшен-коде пользуются оптимизацией не выше -О2, к слову).
Исходный код:
Скрытый текст
#include <string>
// открытый классclass A
{
public:
int x;
double d;
std::string s;
};
//класс с геттерами-сеттерамиclass B
{
public:
int getX() const { return x_; }
void setX(int x) { x_ = x; }
double getD() const { return d_; }
void setD(const double& d) { d_ = d; }
std::string getS() const { return s_; }
void setS(const std::string& s) { s_ = s; }
private:
int x_;
double d_;
std::string s_;
};
// работаем с переменной типа intvoid fiA(A& a)
{
++a.x;
}
void fiB(B& b)
{
int x = b.getX();
++x;
b.setX(x);
}
// работаем с переменной типа doublevoid fdA(A& a)
{
a.d += 100;
}
void fdB(B& b)
{
double d = b.getD();
d += 100;
b.setD(d);
}
// работаем с переменной типа std::stringvoid fsA(A& a)
{
a.s.resize(100);
}
void fsB(B& b)
{
std::string s = b.getS();
s.resize(100);
b.setS(s);
}
// введем еще один (тривиальный) уровень сеттеров-геттеровclass A0
{
public:
A a;
};
class B0
{
public:
B getB() const { return b_; }
void setB(const B& b) { b_ = b; }
private:
B b_;
};
// поехалиvoid fAA(A0& a0)
{
++a0.a.x;
a0.a.d += 100;
a0.a.s.resize(100);
}
void fBB(B0& b0)
{
B b = b0.getB();
int x = b.getX();
++x;
b.setX(x);
double d = b.getD();
d += 100;
b.setD(d);
std::string s = b.getS();
s.resize(100);
b.setS(s);
b0.setB(b);
}
это я еще по-божески обошелся с геттеро-сеттерным кодом — переменную создал только один раз в начале и присвоил обратно только один раз в конце.
Хотя, чтоб делать эквивалентно, надо бы звать get/set на каждый чих (потому что в промежутках могут зваться функции, которым требуется измененное состояние полного объекта).
Но и без этого читабельность кода где-то в районе плинтуса.
к слову, std::string используется из поставки компилятора, а не какой-нть из STLPort с оптимизацией коротких строк, который компилятор не сможет соптимизировать с вероятностью 99.94%.
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
J>>И как, часто в твоей жизни наступало такое вот "завтра"? Только честно. J>>У меня вот чуть чаще чем никогда.
о_О>возникает постоянно при проектировании с нуля, из-за неопытности не всегда получается сделать сразу хорошо. абстрагировался, а там хоть потоп
При проектировании c нуля всегда получается не очень хорошо, поэтому первый вариант называется прототипом и выбрасывается на свалку, а в пользование идет второй, а то и третий, в котором недостатки первого устранены. И неопытность тут совершенно ни при чем — предусмотреть все с самого начала невозможно в принципе. А абстрагировать неудачный первый вариант и потом за фасадом сложных геттеров-сеттеров пытаться перерефакторить все к нормальному виду — путь к тому самому потопу.
Здравствуйте, jazzer, Вы писали:
J>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты.
Да кто ж заставляет-то? Весь разговор пошел с заявления, что геттеры-сеттеры вообще не нужны. Но ведь их вполне можно использовать, когда они облегчают жизнь, а не лепить везде, где не попадя.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>Здравствуйте, jazzer, Вы писали:
J>>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты.
Ops>Да кто ж заставляет-то? Весь разговор пошел с заявления, что геттеры-сеттеры вообще не нужны. Но ведь их вполне можно использовать, когда они облегчают жизнь, а не лепить везде, где не попадя.
не просто геттеры-сеттеры, а "пропертя" и их реализация через геттеры-сеттеры как альтернатива простым публичным членам.
Здравствуйте, MasterZiv, Вы писали:
>> MZ>КЫВТ УГ >> возвращайся на исходнечки.ру
MZ>А это оно само пишет. Я ОДИН раз это написал, оно теперь САМО это посылаяет MZ>Это если через Web писать. Так что все вопросы к программистам RSDN.
Я думаю, что все вопросы к твоей настройке твоего браузера, который один раз запомнил содержимое полей формы и теперь все время одно и то же туда лепит.
У меня FF, никаких "автозаполнятелей" форм нету — полет нормальный.
> Я думаю, что все вопросы к твоей настройке твоего браузера, который один раз > запомнил содержимое полей формы и теперь все время одно и то же туда лепит.
Безусловно. Только как их поменять я лично не имею ни малейшего представления.
А удалить их из этих полей не имею возможности -- они там все слепляются
на телефоне в такую кашу, что я имею возможность ткнуть только в ОДНО
поле, самое большое -- собственно текст сообщения, набрать его там, и потом
нажать "послать".
Я об этом всём писал в отдельном топике, но народ с RSDN-а и его Web-морды
прётся, и ничего слышать не хочет.
Здравствуйте, jazzer, Вы писали:
J>не просто геттеры-сеттеры, а "пропертя" и их реализация через геттеры-сеттеры как альтернатива простым публичным членам.
Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Ops>Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Здравствуйте, IROV.., Вы писали:
IRO>Если по существу, то проектируются всегда от интерфейсов IRO>любое изменение таких данных влечет за собой измененние состояния, IRO>как минимум выставить флаг инвалидации, и в get она проверяется (так называемая линивый пересчет)
IRO>например setPosition, getMatrix IRO>setPosition выставит флаг инвалидации IRO>getMatrix пересчитает матрицу только в том случае если данные изменились, в противном вернет as is
ну и я про это, я просто не хочу писать то, что и так очевидно: set, get и эти, мать их, скобочки.
так я не против изоляции, но я ее намеренно нарушаю потому что меня раздражает писать гет, сет, скобочку сюда, скобочку туда
не тока потому что я не люблю писть то что и так очевидно, а еще потому что этот хлам мешает читать код
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, MasterZiv, Вы писали:
MZ>А это оно само пишет. Я ОДИН раз это написал, оно теперь САМО это посылаяет MZ>Это если через Web писать. Так что все вопросы к программистам RSDN.
Ops>>Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Здравствуйте, jazzer, Вы писали:
N>>Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба. J>Ага. Сколько у нас там операторов? С десяток наберется ведь?
Ну вообще-то больше, а что?
J>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты.
Не "где-то кому-то могут потребоваться", а вообще принципиальная (и очень полезная) концепция представления действий с объектом через привычные действия через его именованные члены.
N>> property foo { N>> void resize(size_t newsize) { this->resize_foo(newsize); } N>> }; J>Те же проблемы, что и с операторами, только еще хуже. Это ж для всех функций-членов всех классов придется подобное писать, и для каждого свое, так что даже в макрос не упрячешь.
Почему *придётся*? Это пишется только там, где оно такое действительно запрошено. Никто не мешает совмещать этот механизм и с открытыми членами, и с геттерами, где надо.
J>Так что овчинка выделки не стоит совершенно.
В варианте, доведённом до абсурда — да, не стоит. В нормальном — не доказано.
<...> J>std::string — туши свет
Конечно, это уже за пределами их понимания, потому что ты делаешь везде копии и не подсказал компилятору никакой оптимизации.
(С другой стороны, вполне возможно, оптимизации тут есть в реализации, за счёт сохранения общего буфера строки и COW на модификации. Поэтому остаются только несколько вызовов функций, которые относительно дёшевы. Но это за пределами темы properties.)
J>// введем еще один (тривиальный) уровень сеттеров-геттеров
И тут, когда не добрались до std::string, проблем нет — всё аккуратно вычитывается напрямую по смещениям и не создаются никакие getB().
J>к слову, std::string используется из поставки компилятора, а не какой-нть из STLPort с оптимизацией коротких строк, который компилятор не сможет соптимизировать с вероятностью 99.94%.
Я не изучал разницу, но не вижу тут принципиальной проблемы. std::string сам по себе достаточно сложный зверь. Никто не обещал тотального упрощения всего и везде. Но вот сделать удобный для человека сахар для важного случая — почему бы и нет?
Ops>>Имена функций (любых, членов и свободных) должны сводиться к ГЛАГОЛУ — этот глагол не должен быть set или get. А когда я вижу аксессоры, я хватаюсь за пистолет.
Здравствуйте, Vamp, Вы писали:
V>Дело не в том, какая приставка, а в том, что они мешают в целом.
Если тебе мешают пары функций, то и не используй их. А ломать инкапсуляцию ради удобства — это дурдом.
К>>Проперти, будучи в языке, внесли бы строгость. Но их нет, и они не внесли. V>Я так и не вижу их преимуществ. Все это неизжитый дельфизм.
Вижуалбейсикизм и олекомизм.
В VC они введены в язык именно для поддержки оле.
К>>А как именно нахлебался? V>Да по-всякому. Я тут уже два раза писал, как половина полезного синтаксиса закрывается. См. выше. V>Кроме этого, усложняется косвенная адресация. Например, есть желание универсально обращаться к полю.
Указатели на члены (-функции и -данные) — это замыкания для голытьбы.
Завернул бы в интерфейс или в пару function<>, и было бы счастье.
Или, если уж хочется по-короткому и на шаблонах, то
template<class C, class Getter, class Setter>
void manipulate(C* obj, Gettter getter, Setter setter, what_t what)
{
typedef PLEASE_EXTRACT_VALUE_TYPE_FROM_MEMBER_FUNCTION(getter) T;
switch(what)
{
case read: (obj->*setter)(get_user_input<T>());
case write: output_to_user(obj->*getter());
}
}
К>>2) нетупое присваивание — валидация; V>И что ты делал, если валидация обламывалась?
А что делают, если валидация обламывается. Или подгонял значение, или исключение кидал. В чём здесь вопрос?
K>>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
MZ>Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
Хинт — пока что-то не сделают, оно нахрен никому не нужно. Например, если бы лет 10 назад спросить на этом форуме — почему нету лямбд, последовал бы ответ — они никому не нужны
Здравствуйте, enji, Вы писали:
MZ>>Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
E>Хинт — пока что-то не сделают, оно нахрен никому не нужно. Например, если бы лет 10 назад спросить на этом форуме — почему нету лямбд, последовал бы ответ — они никому не нужны
А лямбды и сейчас не нужны. Но, суки, удобные.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, jazzer, Вы писали:
N>>>Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба. J>>Ага. Сколько у нас там операторов? С десяток наберется ведь?
N>Ну вообще-то больше, а что?
а то, что с нормальными членами работать удобно, в отличие от пропертей, который либо подерживают только get/set через присваивание, либо надо лепить полную обвязку со всеми операторами.
J>>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты.
N>Не "где-то кому-то могут потребоваться", а вообще принципиальная (и очень полезная) концепция представления действий с объектом через привычные действия через его именованные члены.
какие "привычные действия" имеются в виду? у пропертей только get/set есть по умолчанию.
В то время как для члена типа int "привычными действиями" является весь арсенал операторов, а в случае std::string — еще и функций-членов и свободных функций (std::for_each, например).
N>>> property foo { N>>> void resize(size_t newsize) { this->resize_foo(newsize); } N>>> }; J>>Те же проблемы, что и с операторами, только еще хуже. Это ж для всех функций-членов всех классов придется подобное писать, и для каждого свое, так что даже в макрос не упрячешь.
N>Почему *придётся*? Это пишется только там, где оно такое действительно запрошено. Никто не мешает совмещать этот механизм и с открытыми членами, и с геттерами, где надо.
А где это не запрошено? Кому-то удобнее все через присваивания делать, можно подумать?
Если хочется удобства, то придется. Если удобство не нужно, то конечно, можно ничего не делать.
J>>Так что овчинка выделки не стоит совершенно.
N>В варианте, доведённом до абсурда — да, не стоит. В нормальном — не доказано.
Где ты видишь абсурд?
Вот есть член типа std::string — у него 3 десятка функций-членов, десяток операторов и 3 десятков свободных функций.
Если это просто открытый член — мне весь этот арсенал средств доступен "из коробки".
Если же мы во что бы то ни стало хотим сделать проперть, сохранив при этом сей арсенал, нам придется весь этот интерфейс воспроизвести еще раз в терминах проперти.
Укажи, где именно тут ты увидел абсурд.
N><...> J>>std::string — туши свет
N>Конечно, это уже за пределами их понимания, потому что ты делаешь везде копии и не подсказал компилятору никакой оптимизации. N>(С другой стороны, вполне возможно, оптимизации тут есть в реализации, за счёт сохранения общего буфера строки и COW на модификации. Поэтому остаются только несколько вызовов функций, которые относительно дёшевы. Но это за пределами темы properties.)
Вот именно что за пределами. А делать копии — так другого способа с пропертями нету, простите, если ты хочешь ее менять.
А что именно я должен был подсказать компилятору? Перепиши код, чтоб было "как надо", чтоб компилятор все заоптимизировал.
Не говоря уже о том, что код с пропертями нечитабелен абсолютно по сравнению с кодом прямой работы с членами.
J>>// введем еще один (тривиальный) уровень сеттеров-геттеров
N>И тут, когда не добрались до std::string, проблем нет — всё аккуратно вычитывается напрямую по смещениям и не создаются никакие getB().
Зато когда добрались — туши свет, не?
J>>к слову, std::string используется из поставки компилятора, а не какой-нть из STLPort с оптимизацией коротких строк, который компилятор не сможет соптимизировать с вероятностью 99.94%.
N>Я не изучал разницу, но не вижу тут принципиальной проблемы. std::string сам по себе достаточно сложный зверь. Никто не обещал тотального упрощения всего и везде. Но вот сделать удобный для человека сахар для важного случая — почему бы и нет?
Ну так если это сложный зверь, зачем еще дополнительно усложнять себе жизнь, оборачивая его в проперти?
Здравствуйте, jazzer, Вы писали:
N>>Я не изучал разницу, но не вижу тут принципиальной проблемы. std::string сам по себе достаточно сложный зверь. Никто не обещал тотального упрощения всего и везде. Но вот сделать удобный для человека сахар для важного случая — почему бы и нет?
J>Ну так если это сложный зверь, зачем еще дополнительно усложнять себе жизнь, оборачивая его в проперти?
А кто предлагал такое (всё через get и set) именно для string? Я как раз не предлагал. Обсуждай с тем, кто это предложил и за это агитирует.
Моё предложение было существенно иным — если оно и string, то явно необходимые для сущности конкретного свойства операции должны быть определены явно и само это определение уже даст необходимые оптимизации. А остальные операции спокойно могут быть при необходимости реализованы через дефолтные get и set.
N>>>>Тут есть два выхода. Можно разрешить любые неописанные операции через get-modify-set, а можно какие-то операции явно определить с реализующим их кодом, а не только get и set. Можно использовать оба. J>>>Ага. Сколько у нас там операторов? С десяток наберется ведь? N>>Ну вообще-то больше, а что? J>а то, что с нормальными членами работать удобно, в отличие от пропертей, который либо подерживают только get/set через присваивание, либо надо лепить полную обвязку со всеми операторами.
Ты не то и не с тем сравниваешь.
Сравнивай не прямую работу с членами, а работу через свойства с их неявно определёнными действиями — с явно вызываемыми геттерами, сеттерами и прочими модификаторами. Это когда надо каждый раз писать getTitle(), setTitle(), expandTitle() и так далее, потому что прямого присвоения недостаточно — например, setTitle() может требовать немедленной перерисовки на экране или переиндексации в базе. В случае отсутствия свойств как элемента языка тебе требуется пачка функций по управлению содержимым — то есть тот кошмар, на который, например, ругается Vamp; но его не избежать, если в принципе возможно, что какой-то член класса является не просто куском данных, который в нём лежит для общности, но и имеет какое-то семантическое отражение внутри (как заголовок окна для класса окна).
J>Не говоря уже о том, что код с пропертями нечитабелен абсолютно по сравнению с кодом прямой работы с членами.
Это с чего вдруг? Для доступа извне реализации класса разницы никакой вообще, синтаксис идентичен.
Для внутри — наоборот, он в разы читабельнее, если мы имеем, аналогично предыдущему примеру, property{} с определением действий — вместо адских шаблонных наворотов, которые потребуются, если мы будем обеспечивать те же эффекты за счёт того, что членом класса будет другой специальный класс, который возьмёт на себя необходимые переопределения операций.
Если ты определишь, например, для строки операцию взятия значения, дописки в конец и установки нового значения через
это сильно просто по сравнению с тем, что потребуется, если определять класс, который будет реагировать на установку значения, например, вызовом assert_correct_title() у объекта-владельца. И писать это кошмарно, и скорее всего дороже в рантайме — потому что потребуется хранить ссылку на владельца. Может, кто-то сможет шаблонами упростить это — чтобы компилировалось уже со знанием конкретного владельца; я достаточно паршиво знаю систему плюсовых шаблонов и не в курсе, могут ли они вытянуть такое, чтобы избавиться от лишних ссылок. Но если может, то это всё равно кошмарный кусок кода в худших традициях шаблонизации. А в виде свойства всё получается красиво и просто.
J>>>И вся эта карусель лишь ради того, что "Вдруг Когда-то Где-то Кому-то" (tm) могут потребоваться сайд-эффекты. N>>Не "где-то кому-то могут потребоваться", а вообще принципиальная (и очень полезная) концепция представления действий с объектом через привычные действия через его именованные члены. J>какие "привычные действия" имеются в виду? у пропертей только get/set есть по умолчанию.
Это потому, что ты смотришь на то, как они определены в тех языках, где есть.
А я не хочу ограничиваться именно таким представлением (хотя и оно достаточно неплохо, если не вызывает огромных накладных расходов). Что мешает определить и другие операции?
Более того, почему ты вообще говоришь про get и set? Представь себе, что это не свойство, а обычная переменная. Ты будешь о ней говорить в терминах get и set? Нет, в случае C++ ты будешь думать о, например, operator int() для присвоения целому, operator double() для присвоения плавающему, и перегруженному operator =(...) для присвоения уже ему значения какого-то типа.
Так при чём тут get и set?
J>В то время как для члена типа int "привычными действиями" является весь арсенал операторов, а в случае std::string — еще и функций-членов и свободных функций (std::for_each, например).
И тут будет то же самое, если реализовывать в стиле C++, а не копировать логику, которая адекватна, может быть, для языка стиля Python. Другая семантика — другая логика. J>>>Так что овчинка выделки не стоит совершенно. N>>В варианте, доведённом до абсурда — да, не стоит. В нормальном — не доказано. J>Где ты видишь абсурд?
Абсурд именно в ограничении набором из get и set, даже не параметризованных.
J>Вот есть член типа std::string — у него 3 десятка функций-членов, десяток операторов и 3 десятков свободных функций. J>Если это просто открытый член — мне весь этот арсенал средств доступен "из коробки". J>Если же мы во что бы то ни стало хотим сделать проперть, сохранив при этом сей арсенал, нам придется весь этот интерфейс воспроизвести еще раз в терминах проперти.
Не весь. А только тот, что нужен для данного случая. Да, он будет ограничен. Но само по себе property — это метод ограничения и управления доступом к классу, так что тут такое естественно.
J>Вот именно что за пределами. А делать копии — так другого способа с пропертями нету, простите, если ты хочешь ее менять.
И до седмижды семидесяти: не думай о свойствах в стиле других языков. Мы в теме C++, так что думай о том, как они должны были бы быть реализованы для C++.
J>А что именно я должен был подсказать компилятору? Перепиши код, чтоб было "как надо", чтоб компилятор все заоптимизировал.
Не буду, ибо незачем. Правильно — выставить именно нужные операции оптимальным способом, а не придумывать методы обхода через дальнее болото.
Здравствуйте, Kingofastellarwar, Вы писали:
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
K>разве не лучше писать Core->SystemA->Manager->Call(); K>чем GetCore()->GetSystemA()->GetManager()->Call(); K>? K>или еще хуже с разными с порнонотациями типа : K>getCore()->getSystemA()->getManager()->Call(); K>или полные дрова: K>get_Core()->get_SystemA()->get_Manager()->Call();
K>я из за этого уродства забил на изоляцию мемберов от внешнего мира и использую паблик мемберы по полной.
K>почему в 11-м стандарте предложена куча всякой ультраспецифичной лабуды, а такого ништяка до сих пор там нет?
K>(костыли и мс-специфичные прагмы не предлагать, пробовал уже)
Я вот так извращался что бы поиметь пропертя, они были нужны для реализации MVC и таких полей было тьма:
объявление и использование полей в принципе оказалось вполне приемлемым. Короткий синтаксис объявления +начальное значение.
Не очень сложно использовать. Подсказки по коду тоже работают.
Проблемы были только с методом Assign его постоянно надо поддерживать в актуальном состоянии. Ну нету в C++ reflection.
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
J>>В том виде, в котором они в С++, они ни разу не удобные
о_О>обоснуй, пожалуйста, и приведи пример
они мономорфные, типы надо явно указывать, что тут еще обосновывать...
Здравствуйте, netch80, Вы писали:
N>Сравнивай не прямую работу с членами, а работу через свойства с их неявно определёнными действиями — с явно вызываемыми геттерами, сеттерами и прочими модификаторами. Это когда надо каждый раз писать getTitle(), setTitle(), expandTitle() и так далее, потому что прямого присвоения недостаточно — например, setTitle() может требовать немедленной перерисовки на экране или переиндексации в базе.
Ну и зачем нужны эти грабли? Когда ты типа с переменной работаешь, а её какие-то добрые люди потом пропертёй обернули и каждый ++ перестройку индексов к терробайтной базе рожает?
N>В случае отсутствия свойств как элемента языка тебе требуется пачка функций по управлению содержимым — то есть тот кошмар, на который, например, ругается Vamp;
Дык интерфейс надо по-человечески проектировать.
Например, зачем заголовкам окон что-то кроеме сета и гета? Ну там, какой-нибудь find зачем?
На крайняк можно константный доступ дать...
N>Это с чего вдруг? Для доступа извне реализации класса разницы никакой вообще, синтаксис идентичен.
Да в том-то и беда, что написанно может быть одно и то же, а делать при этом совсем разное...
N>А я не хочу ограничиваться именно таким представлением (хотя и оно достаточно неплохо, если не вызывает огромных накладных расходов). Что мешает определить и другие операции?
Ну заводишь пачку интерфейсов и вперёд
N>И до седмижды семидесяти: не думай о свойствах в стиле других языков. Мы в теме C++, так что думай о том, как они должны были бы быть реализованы для C++.
Я думаю, что в С++ они противоестественны.
Хороший С++ объект не должен ничего знать о своём владельце.
В логику С++ хорошо ложился бы механизм, позволяющий заводить как-то ограниченные наборы методов класса-параметра + подписка на вызов методов.
Ну типа пишешь что-то типа SeperVar<std::string>{ тут перечисляешь как-то нужные методы } myString.
И потом на эту myString можно подписаться
Но такую конструкцию можно и сейчас соорудить, вообще-то.
Будет немного не так, конечно, но тоже ничего
struct MyTitleString : SuperVar<std::string> {
// тут дописываешь методы, кроме get и set
} myTitle;
Только не понятно на кой оно всё надо...
Реально вся тема с пропертями упирается в две проблемы.
1) В С++ очень убогие шаблоны. Они конечно мощны для извратов, но без извратов не работают почти никак.
2) Имея указатель на один и тот же объект, как на член и как на данные, нельзя получить указатель на аггрегирующий объект. Ясно, что в некоторых случаях это невозможно чисто технически. Но в некоторых-то возможно. Но нельзя никогда.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Abyx, Вы писали:
A>например, имеем код
A>
A>struct Foo
A>{
A> int state;
A>};
A>
A>и пару сотен использований токена "state" в исходниках. A>надо понять где, как и зачем state меняется, и например добавить туда новый код (в setter)
Просто пишем, что это const int state и по списку ошибок компиляции узнаём места...
А твой подход сильно сломается, если на поле берут указатель и куда-то отдают бродить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
N>>Сравнивай не прямую работу с членами, а работу через свойства с их неявно определёнными действиями — с явно вызываемыми геттерами, сеттерами и прочими модификаторами. Это когда надо каждый раз писать getTitle(), setTitle(), expandTitle() и так далее, потому что прямого присвоения недостаточно — например, setTitle() может требовать немедленной перерисовки на экране или переиндексации в базе. E>Ну и зачем нужны эти грабли? Когда ты типа с переменной работаешь, а её какие-то добрые люди потом пропертёй обернули и каждый ++ перестройку индексов к терробайтной базе рожает?
Почти верно. Когда ты типа с переменной работаешь, а её какие-то добрые люди пропертей обернули и каждый ++ побочные эффекты рожает... а что, ты всерьёз думаешь, что перестройка индекса будет такая сложная? А какая тогда разница по сравнению с setFoo(getFoo()+1)? Только то, что не знаешь, просто это переменная или что-то иное? Так для этого документация есть.
N>>В случае отсутствия свойств как элемента языка тебе требуется пачка функций по управлению содержимым — то есть тот кошмар, на который, например, ругается Vamp; E>Дык интерфейс надо по-человечески проектировать. E>Например, зачем заголовкам окон что-то кроеме сета и гета? Ну там, какой-нибудь find зачем?
Не знаю, это тебя надо спросить. Я никакого find тут не предлагал.
E>Да в том-то и беда, что написанно может быть одно и то же, а делать при этом совсем разное...
"Это Спарта!!!" В смысле, это C++. Или вообще любой "взрослый" язык программирования, в котором операция, выглядящая как простое сложение, может переворачивать атомоходы, отстреливать айсберги и двигать материки.
N>>А я не хочу ограничиваться именно таким представлением (хотя и оно достаточно неплохо, если не вызывает огромных накладных расходов). Что мешает определить и другие операции? E>Ну заводишь пачку интерфейсов и вперёд
И что? Не понимаю глубокой мысли.
N>>И до седмижды семидесяти: не думай о свойствах в стиле других языков. Мы в теме C++, так что думай о том, как они должны были бы быть реализованы для C++. E>Я думаю, что в С++ они противоестественны. E>Хороший С++ объект не должен ничего знать о своём владельце.
А это и не объект. Это свойство. Это совершенно другое понятие, и привлекать к нему хоть какую-то логику объекта бессмысленно.
E>Только не понятно на кой оно всё надо...
Удобно для программиста. В язык вводят кучу фишек и значительно менее удобных и важных.
E>Реально вся тема с пропертями упирается в две проблемы. E>1) В С++ очень убогие шаблоны. Они конечно мощны для извратов, но без извратов не работают почти никак. E>2) Имея указатель на один и тот же объект, как на член и как на данные, нельзя получить указатель на аггрегирующий объект. Ясно, что в некоторых случаях это невозможно чисто технически. Но в некоторых-то возможно. Но нельзя никогда.
Это всё потому, что вместо поддержки компилятора ты думаешь об извратах, как это всё сделать с теми средствами, что сейчас. Конечно, ничего хорошего не получится.
Здравствуйте, Ops, Вы писали:
Ops>Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет.
Забавно, все стали упоминать про побочные эффекты в геттерах/сеттерах — редкий и сомнительный case.
А защиту состояния объекта от ломающих изменений почему-то никто не вспомнил
Здравствуйте, 0x7be, Вы писали:
0>Здравствуйте, Ops, Вы писали:
Ops>>Кроме доступа там могут быть какие-то сайд-эффекты прикручены, уведомить кого-то об изменении переменной, например. Так что ничего плохого в set/get нет. 0>Забавно, все стали упоминать про побочные эффекты в геттерах/сеттерах — редкий и сомнительный case. 0>А защиту состояния объекта от ломающих изменений почему-то никто не вспомнил
Потому что для прямой защиты достаточно явных методов get, set.
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
J>>они мономорфные, типы надо явно указывать, что тут еще обосновывать...
о_О>Это С++, а не Йуморле. Большего ожидать не стоит.
Никаких принципиальных проьблем сделать это в С++ я лично не вижу.
Boost.Lambda как-то с этим справляется в рамках С++: _1 < _2.
Вот это — хороший, годный синтаксис для лямбд.
Вот таким он примерно и должен быть, только должен быть встроенным в язык, чтоб были плюшки в виде нормальной диагностики и т.д.
На самом деле, нынешние лямбды — это просто сахар для объявления/определения локального класса-функтора.
И чтоб его можно было использовать со всякими std::for_each, пришлось поменять стандарт и явно разрешить параметризовать шаблоны локальными классами.
Полиморфные лябмды а ля Boost.Lambda элементарно реализуются аналогичным образом, только оператор у функтора должен быть шаблонным, что сейчас запрещено для локальных классов. Если это разрешить — получим нормальные полиморфные лябмды, т.е. такая запись
> Хинт — пока что-то не сделают, оно нахрен никому не нужно. Например, если бы лет > 10 назад спросить на этом форуме — почему нету лямбд, последовал бы ответ — они > никому не нужны
Здравствуйте, jazzer, Вы писали:
J>Вот таким он примерно и должен быть, только должен быть встроенным в язык, чтоб были плюшки в виде нормальной диагностики и т.д.
вот она главная проблема: старые маразматики из комитета назвали направление развития "путем расширения стандартной библиотеки" (отсюда убогие std::function, std::bind вместо нормальных делегатов, примитивные лямбды, всякие noexcept, std::begin без std::rbegin — это вообще facepalm)).
Здравствуйте, netch80, Вы писали:
N>А какая тогда разница по сравнению с setFoo(getFoo()+1)? Только то, что не знаешь, просто это переменная или что-то иное? Так для этого документация есть.
Ну, кроме того, что очевидно, что setFoo(getFoo()+1) может быть чем-то небыстрым, мы не можем получить указаель на такую штуку, например.
N>Не знаю, это тебя надо спросить. Я никакого find тут не предлагал.
Ну я вообще не понимаю о чём речь, видимо.
Если свойство не объект, а просто группа методов, как-то синтаксически выделенная, ну типа аналог вложенного namespace, то зачем оно вообще надо?
Может таки классы нормально проектировать и не страдать?
N>"Это Спарта!!!" В смысле, это C++.
Дык зачем усугублять-то?
E>>Ну заводишь пачку интерфейсов и вперёд N>И что? Не понимаю глубокой мысли.
Ну давай ты какой-то пример напишешь как бы было здорово, если бы то, что ты называешь свойствами, было в С++.
Пример класса с такими свойствами + пример использоваия этого класса.
А потом подумаем, может в С++ уже есть какие-то общепринятые способы написанияи таких классов?
N>А это и не объект. Это свойство. Это совершенно другое понятие, и привлекать к нему хоть какую-то логику объекта бессмысленно.
Ну, то есть, например, на него нельзя взять указатеь, скажем?
N>Удобно для программиста. В язык вводят кучу фишек и значительно менее удобных и важных.
imho, С++ достиг такого уровня развития, что самое удобное, для программиста -- это начать выкидывать
Но ты приведи пример кода, как бы оно было, если бы всё уже было. А то пока что не понятно, за что ты воевать-то хочешь.
N>Это всё потому, что вместо поддержки компилятора ты думаешь об извратах, как это всё сделать с теми средствами, что сейчас. Конечно, ничего хорошего не получится.
Да мне просто кажется, что ты хочешь решить какую-то частную проблему. Я правда пока не понял какую. А суть проблем в другом месте лежит.
Вот смотри, мне бы, например, намного больше, чем свойства, было бы интересно, если бы я мог описать такой вложенный класс, единственный экземпляр которого всегда был бы полем объёмлющего. Ну что-то типа
class Master {
// bla-bla-bla class {
// тут описание
} slaver;
}
и в slaver я мог бы как-то просто получить this его Master'а
Тогда много всяких хитрых задач решалось бы без хаков...
И что-то очень похожее на проперти ложилось бы тоже хорошо.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Abyx, Вы писали:
A>>например, имеем код
A>>
A>>struct Foo
A>>{
A>> int state;
A>>};
A>>
A>>и пару сотен использований токена "state" в исходниках. A>>надо понять где, как и зачем state меняется, и например добавить туда новый код (в setter)
E>Просто пишем, что это const int state и по списку ошибок компиляции узнаём места...
при этом будут лишние ошибки изза оператора присваивания
E>А твой подход сильно сломается, если на поле берут указатель и куда-то отдают бродить...
Здравствуйте, Erop, Вы писали:
E>imho, С++ достиг такого уровня развития, что самое удобное, для программиста -- это начать выкидывать
зачем выкидывать? че за бред? не хочешь — не юзай.
вообще этото маразм отцов с++ по сохранению совместимости мне не понятен.
в дотнете мне кажется подход с фреймворками самый адекватный.
выпускаем с++ 2.0, который грубо и пошло вращал на .... совместимость с 1.0
все кому ништяки 2.0 не нужны продолжают сидеть на 1.0 — и это правильно
теже кто посовещавший и решив что 2.0 круче и они хотят его ништяки и готовы переписать какой-то % кода, то взвесив все садятся и переводят проект на 2.0 — и это тоже правильно
в с++ тот же стл это просто анекдот, сам автор стл говорит что стл — это практически первая попытка в истории создать набор реюзабельного кода.
т.е. оно не просто морально устарело, это вообще не полноценная либа, а попытка, прототип, концепт.
очевидно неудачный, как по мне в первую очередь потому что в стл парадигма победила практичность, типа алгоритмы отдельно, контенеры отдельно — как красиво....и неудобно.
т.е. программеры сами решают нужно им использовать свежую версию или нет, и я думаю 95% спокойно сможет переходить на новые версии,
только очень древние огромные проекты может оказаться нерентабельно переписывть
а из-за того что стандартизаторы с++ застряли в 80-х, эти 95% проектов вынуждены торчать в 80-х вместе с этими старыми пердунами
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
A>при этом будут лишние ошибки изза оператора присваивания
не понял. Ты хочешь найти все места модификации поля структуры или что?
E>>А твой подход сильно сломается, если на поле берут указатель и куда-то отдают бродить...
A>таких мест не должно быть вообще.
Почему? Особенно если ссылка константная?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Abyx, Вы писали:
A>>>>
A>>>>struct Foo
A>>>>{
A>>>> int state;
A>>>>};
A>>>>
A>>при этом будут лишние ошибки изза оператора присваивания E>не понял. Ты хочешь найти все места модификации поля структуры или что?
ок, тут const может помочь, если мест где используется поле немного
E>>>А твой подход сильно сломается, если на поле берут указатель и куда-то отдают бродить...
A>>таких мест не должно быть вообще. E>Почему? Особенно если ссылка константная?
для
public: trivial_type field;
это нарушает инкапсуляцию и связывает время жизни объектов
Здравствуйте, Kingofastellarwar, Вы писали:
K>только очень древние огромные проекты может оказаться нерентабельно переписывть K>а из-за того что стандартизаторы с++ застряли в 80-х, эти 95% проектов вынуждены торчать в 80-х вместе с этими старыми пердунами
И что, например, ты бы выкинул?..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
A>ок, тут const может помочь, если мест где используется поле немного
А если мнооо, то что? E>>>>А твой подход сильно сломается, если на поле берут указатель и куда-то отдают бродить...
A>>>таких мест не должно быть вообще. E>>Почему? Особенно если ссылка константная?
A>для A>public: trivial_type field; A>это нарушает инкапсуляцию и связывает время жизни объектов
Почему?
например, я могу где-то считать контрольную сумму, и туда скармливать цепочки интов.
одинокий инт -0 это цепочка из одного инта...
опять же, если ты считаешь, что указатель и, видимо ссылку, брать нельзя, то можно написать простой шаблон, от типа поля, который позволяет то, что можно и не позволяет остальное.
заменить переменную на такой тип и выкрутиться без пропертей, например, если компиллер их не умеет
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>И что, например, ты бы выкинул?..
вообще-то я там написал что я не сторонник выкидываний,
я бы скорее переделал некоторые старые вещи и добавил новые
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали:
K>Здравствуйте, IROV.., Вы писали:
IRO>>Если по существу, то проектируются всегда от интерфейсов IRO>>любое изменение таких данных влечет за собой измененние состояния, IRO>>как минимум выставить флаг инвалидации, и в get она проверяется (так называемая линивый пересчет)
IRO>>например setPosition, getMatrix IRO>>setPosition выставит флаг инвалидации IRO>>getMatrix пересчитает матрицу только в том случае если данные изменились, в противном вернет as is
K>ну и я про это, я просто не хочу писать то, что и так очевидно: set, get и эти, мать их, скобочки.
K>так я не против изоляции, но я ее намеренно нарушаю потому что меня раздражает писать гет, сет, скобочку сюда, скобочку туда K>не тока потому что я не люблю писть то что и так очевидно, а еще потому что этот хлам мешает читать код
Я обратного мнения, вообще много кода, это признак того что вы не знаете что писать.
Это как в том выражени "Извини, много написал, было мало времени"
Когдато ты поймешь прелесть инкапсуляции, она схожа с прелестями функционального программирования, также полюбишь const в методах, потомучто будешь уверен что ты сможешь взять эти данные только у константного обьекта.
Здравствуйте, Kingofastellarwar, Вы писали:
K>вообще-то я там написал что я не сторонник выкидываний, K>я бы скорее переделал некоторые старые вещи и добавил новые
Хорошо, что бы ты переделал, и на что?
Я бы, например, написал бы ещё одну стандартную билиотеку, которая не заготовка для написания библиотек, а просто фреймворк для написания программ...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Я бы, например, написал бы ещё одну стандартную билиотеку, которая не заготовка для написания библиотек, а просто фреймворк для написания программ...
по большому мои пожелания скасаются в меньшей степени синтаксиса, чем в инфрастурктуре, так сказать
1. категорически согласен про стл
2. убрать инклудинг и разделение на .h и .cpp, заменить всё на юзинг
3. добавить метаданные, полный ртти
4. добавить поддержку ABI
5. позволить опционально использовать сборщик мусора, сборщик мусора должен быть при необходимости заменяем на любой кастомный
6. шаблоны — пусть отсаются, если я их не использую, то я почти не чувствую, что они сущесвуют, в общем мне оно не мешает
7. добавить пропертя
6. сделать синтаксическую поддержку нескольких базовых классов, типа IEnumerable для foreach, может не так как управляемых, а по другому, гибче, в общем главное не перестараться
8. ну еще какие-то мелочи синтаксические
для с++ 2.0 я думаю хватит
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
K>2. убрать инклудинг и разделение на .h и .cpp, заменить всё на юзинг K>3. добавить метаданные, полный ртти K>4. добавить поддержку ABI K>5. позволить опционально использовать сборщик мусора, сборщик мусора должен быть при необходимости заменяем на любой кастомный K>6. шаблоны — пусть отсаются, если я их не использую, то я почти не чувствую, что они сущесвуют, в общем мне оно не мешает K>7. добавить пропертя K>6. сделать синтаксическую поддержку нескольких базовых классов, типа IEnumerable для foreach, может не так как управляемых, а по другому, гибче, в общем главное не перестараться K>8. ну еще какие-то мелочи синтаксические
Такие языки уже есть. Называются Java, .NET. Превращать С++ в Джаву никакого смысла нет, да и стремно — можно нарваться на патентный иск со стороны Оракла.
А тебе всерьез следует задуматься о смене языка. Судя по всему, С++ не для тебя.
Здравствуйте, Vamp, Вы писали:
V>Такие языки уже есть. Называются Java, .NET. Превращать С++ в Джаву никакого смысла нет, да и стремно — можно нарваться на патентный иск со стороны Оракла. V>А тебе всерьез следует задуматься о смене языка. Судя по всему, С++ не для тебя.
язык программирования это не религия и тем более религиозный подход тут неуместен, я пишу и на том и на том одновременно
и если в управляемых языках что-то сделано реально хорошо и оно применимо к неуправляемым то я не вижу никаких причин не внедрить это не только в с++ а вообще во все языки где это может пригодиться
а ваш подход, это даже не дремучий консерватизм, это скорее религиозный фундаментализм и он противен мне как стороннику технологического прогресса
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Vamp, Вы писали:
V>Такие языки уже есть. Называются Java, .NET. Превращать С++ в Джаву никакого смысла нет, да и стремно — можно нарваться на патентный иск со стороны Оракла. V>А тебе всерьез следует задуматься о смене языка. Судя по всему, С++ не для тебя.
и вообще что это за подход "не для тебя"? я не отношусь к технологиям с симпатиями или антипатиями, это к женщинам такие категории применимы, а с технологиями не может быть никаких интимных чувств.
есть целесообразность и эффективность — и всё, больше ничего не имеет значения и поэтому, для меня внедрить в с++ вещи из шарпа и жабы следует не потому, что это будет няшно, а потому что это целесообразно и всё.
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
K>язык программирования это не религия и тем более религиозный подход тут неуместен,
Никакой религии тут нет. Не надо пытаться использовать микроскоп вместо молотка, и наоборот. С++ — это инструмент. У него есть своя область применимости. Не надо пытаться превращать его в другой инструмент, другой инструмент уже есть. Не подходит С++ для твоих целей — используй управляемые языки, а С++ оставь в покое. Не надо прикручивать к микроскопу боек, он все равно будет плохим молотком.
K>и если в управляемых языках что-то сделано реально хорошо и оно применимо к неуправляемым то я не вижу никаких причин не внедрить это не только в с++ а вообще во все языки где это может пригодиться
Потому что для разных целей нужны разные инструменты, пойми.
K>а ваш подход, это даже не дремучий консерватизм, это скорее религиозный фундаментализм и он противен мне как стороннику технологического прогресса
Прогресс тут вообще не при чем. Молоток — он может и более старый инструмент, чем микроскоп, но это не значит, что все молотки следует заменить на микроскопы.
K>и вообще что это за подход "не для тебя"? я не отношусь к технологиям с симпатиями или антипатиями, это к женщинам такие категории применимы, а с технологиями не может быть никаких интимных чувств.
Ну и зря. Если не любить технологию, которой пользуешься, то никогда не добьешься в ней успеха. Будешь не программист, а кодер. Надо любить то, чем занмаешься, и находить в этом кайф, иначе зачем вообще все это?
K>есть целесообразность и эффективность — и всё, больше ничего не имеет значения и поэтому, для меня внедрить в с++ вещи из шарпа и жабы следует не потому, что это будет няшно, а потому что это целесообразно и всё.
А еще ты неправильно понимаешь целесообразность, что, кстати, проистекает от отсутствия любви к технологии. Любовь вообще краеугольный камень, все, что делаешь, надо делать с любовью, иначе будет получаться хреново.
Здравствуйте, Vamp, Вы писали:
K>>язык программирования это не религия и тем более религиозный подход тут неуместен, V>Никакой религии тут нет. Не надо пытаться использовать микроскоп вместо молотка, и наоборот. С++ — это инструмент. У него есть своя область применимости. Не надо пытаться превращать его в другой инструмент, другой инструмент уже есть. Не подходит С++ для твоих целей — используй управляемые языки, а С++ оставь в покое. Не надо прикручивать к микроскопу боек, он все равно будет плохим молотком.
K>>и если в управляемых языках что-то сделано реально хорошо и оно применимо к неуправляемым то я не вижу никаких причин не внедрить это не только в с++ а вообще во все языки где это может пригодиться V>Потому что для разных целей нужны разные инструменты, пойми.
K>>а ваш подход, это даже не дремучий консерватизм, это скорее религиозный фундаментализм и он противен мне как стороннику технологического прогресса V>Прогресс тут вообще не при чем. Молоток — он может и более старый инструмент, чем микроскоп, но это не значит, что все молотки следует заменить на микроскопы.
да я в общем и не говорил что мне именно с++ нужен, мне нужен неуправляемый компилируемый в нативный код язык с современным синтаксисом, либами, метаданными и прочим
такого нет,
а мне нужен, потому что меня напрягает старческий маразм с++ и тормоза всего и вся в управляемых языках
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Vamp, Вы писали:
K>>и вообще что это за подход "не для тебя"? я не отношусь к технологиям с симпатиями или антипатиями, это к женщинам такие категории применимы, а с технологиями не может быть никаких интимных чувств. V>Ну и зря. Если не любить технологию, которой пользуешься, то никогда не добьешься в ней успеха. Будешь не программист, а кодер. Надо любить то, чем занмаешься, и находить в этом кайф, иначе зачем вообще все это?
K>>есть целесообразность и эффективность — и всё, больше ничего не имеет значения и поэтому, для меня внедрить в с++ вещи из шарпа и жабы следует не потому, что это будет няшно, а потому что это целесообразно и всё. V>А еще ты неправильно понимаешь целесообразность, что, кстати, проистекает от отсутствия любви к технологии. Любовь вообще краеугольный камень, все, что делаешь, надо делать с любовью, иначе будет получаться хреново.
так я и люблю, саму деятельность, а к языкам я отношусь как инструментам, мне не нужно любить инстументы и не нужно любить языки, точно так же как мне не нужно любить конденсаторы в цепях питания моего процессора, мне достаточно того, чтобы они эффективно выполняли свою функцию — реализоывать мои задумки и фильтровать помехи по питанию.
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
K>по большому мои пожелания скасаются в меньшей степени синтаксиса, чем в инфрастурктуре, так сказать
K>1. категорически согласен про стл K>2. убрать инклудинг и разделение на .h и .cpp, заменить всё на юзинг K>3. добавить метаданные, полный ртти K>4. добавить поддержку ABI K>5. позволить опционально использовать сборщик мусора, сборщик мусора должен быть при необходимости заменяем на любой кастомный K>6. шаблоны — пусть отсаются, если я их не использую, то я почти не чувствую, что они сущесвуют, в общем мне оно не мешает K>7. добавить пропертя K>6. сделать синтаксическую поддержку нескольких базовых классов, типа IEnumerable для foreach, может не так как управляемых, а по другому, гибче, в общем главное не перестараться K>8. ну еще какие-то мелочи синтаксические
Почему не использовать C# ?
---
сообщение выше, для меня прозвучало похожим следующему
было бы замечательно добавить в C++:
— нумерацию statement-ов
— убрать контроль типов (а то только жить мешает)
— ну и возможность интерпретации на виртуальной машине
в результате, хочется спросить "Зачем?"
ведь все это уже есть, пользуйся — пожайлуста, в другом языке
Только на РСДН помимо ответа на вопрос, можно получить еще список орфографических ошибок и узнать что-то новое из грамматики английского языка (c) http://www.rsdn.ru/forum/cpp/4720035.1.aspx
Здравствуйте, Vamp, Вы писали:
K>>и вообще что это за подход "не для тебя"? я не отношусь к технологиям с симпатиями или антипатиями, это к женщинам такие категории применимы, а с технологиями не может быть никаких интимных чувств. V>Ну и зря. Если не любить технологию, которой пользуешься, то никогда не добьешься в ней успеха. Будешь не программист, а кодер. Надо любить то, чем занмаешься, и находить в этом кайф, иначе зачем вообще все это?
K>>есть целесообразность и эффективность — и всё, больше ничего не имеет значения и поэтому, для меня внедрить в с++ вещи из шарпа и жабы следует не потому, что это будет няшно, а потому что это целесообразно и всё. V>А еще ты неправильно понимаешь целесообразность, что, кстати, проистекает от отсутствия любви к технологии. Любовь вообще краеугольный камень, все, что делаешь, надо делать с любовью, иначе будет получаться хреново.
любовь...а еще говоришь, что никакой религиозности,
но спасибо, теперь хоть ясно на чем твой консерватизм стоит, на любви к с++, а я тут про эффективность, прогрессивность распинаюсь...
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Serjio, Вы писали:
S>сообщение выше, для меня прозвучало похожим следующему
было бы замечательно добавить в C++:
S>— нумерацию statement-ов
S>— убрать контроль типов (а то только жить мешает)
S>— ну и возможность интерпретации на виртуальной машине
в результате, хочется спросить "Зачем?" S>ведь все это уже есть, пользуйся — пожайлуста, в другом языке
потому что мне нужно скорость всего
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
а вот, отправив увидел, ответ на вопрос: "нужен неуправляемый язык"
тогда sorry
возможно в этом кроется ответ, и на вопрос о свойствах в C++
не тот ответ, что было бы приятно получить, но он имеет на это право.
(да и сказано весьма тактично)
Только на РСДН помимо ответа на вопрос, можно получить еще список орфографических ошибок и узнать что-то новое из грамматики английского языка (c) http://www.rsdn.ru/forum/cpp/4720035.1.aspx
Здравствуйте, jazzer, Вы писали:
J>Полиморфные лябмды а ля Boost.Lambda элементарно реализуются аналогичным образом, только оператор у функтора должен быть шаблонным, что сейчас запрещено для локальных классов. Если это разрешить — получим нормальные полиморфные лябмды, т.е. такая запись
Где-то читал, что такие лямбды плохо совместимы с концептами, поэтому их не стали делать. А потом и концепты отвалились
Здравствуйте, о_О, Вы писали:
о_О>вот она главная проблема: старые маразматики из комитета назвали направление развития "путем расширения стандартной библиотеки" (отсюда убогие std::function,
гм. Чем убог function? Для делегатов есть signal2, вполне себе неплох.
Здравствуйте, B0FEE664, Вы писали:
BFE>На мой вкус этот код выглядит подозрительно. Зачем lock при публичном методе g()? Почему допускается такая операция: BFE>
BFE>? А если это легально, то зачем тогда нужен lock?
да.
Но основная модели оповещает своих подписчиков об изменении полей.
если написать
a.g()=10;
a.g()=b.g();
то дважды будут оповещены подписчики.
а если сделать
lock то только по выходу из лока. причем локи могу быть вложенными
это что бы можно было менять группу полей без лишних оповещений.
...черт. не туда нажал. ...
_>Здравствуйте, B0FEE664, Вы писали:
BFE>>На мой вкус этот код выглядит подозрительно. Зачем lock при публичном методе g()? Почему допускается такая операция: BFE>>
BFE>>? А если это легально, то зачем тогда нужен lock?
да легально. лок нужен для блокировки оповещений.
Основная задача модели оповещать своих подписчиков об изменении полей.
если написать
a.g()=10;
a.g()=b.g();
то дважды будут оповещены подписчики.
а если сделать lock то только по выходу из лока. причем локи могу быть вложенными
это что бы можно было менять группу полей без лишних оповещений.
схема простая как валенок.
вот остаток кода если вдруг интересно поэкспериментировать.
Notifier.cpp
#include "Notifier.h"
#define ERR_MODIFY_READONLY "modify in readonly mode"
#define ERR_LOCK_READONLY "unable to lock in readonly mode"
#define ERR_ALREADY_SUBSCRIBED "listener already subscibed"
#define ERR_NOT_SUBSCRIBED "listener not registered"
#define ERR_HAS_CHILD "this node already attached"
#define ERR_NO_CHILD "no such child node found"
#define ERR_BAD_LOCK_LEVEL "lock_level must be 0"
#define ERR_BAD_LOCK_LEVEL_RO "lock_level<0 must be 0"
void throw_exception(const char* reason) {
throw reason;
}
Notifier::Notifier() {
lock_level=0;
modified=false;
}
Notifier::~Notifier() {
if (lock_level!=0) {
// fatal error!
lock_level=lock_level;
}
}
void Notifier::Modified() {
modified=true;
if (lock_level>0) return;
if (lock_level<0) throw_exception(ERR_MODIFY_READONLY);
NotifyAll();
}
void Notifier::NotifyChange() {
Modified();
}
void Notifier::Lock() {
if (lock_level<0) throw_exception(ERR_LOCK_READONLY);
if (++lock_level==1) LockChildren();
}
void Notifier::Unlock() {
if (--lock_level==0) {
lock_level++;
UnlockChildren();
lock_level--;
if (modified) NotifyAll();
}
}
void Notifier::AttachChild(Notifier& child) {
if (children.find(&child)!=children.end()) throw_exception(ERR_HAS_CHILD);
children.insert(&child);
if (lock_level>0) child.Lock();
child.Subscribe(*this,!modified && child.IsModified());
}
void Notifier::DetachChild(Notifier& child) {
children_it it=children.find(&child);
if (it==children.end()) throw_exception(ERR_NO_CHILD);
children.erase(it);
child.Unsubscribe(*this);
if (lock_level>0) child.Unlock();
}
void Notifier::Subscribe(NotifyListener &listener,bool notify_attach) {
if (listeners.find(&listener)!=listeners.end()) throw_exception(ERR_ALREADY_SUBSCRIBED);
listeners.insert(&listener);
if (notify_attach) listener.NotifyChange();
}
void Notifier::Unsubscribe(NotifyListener &listener) {
listeners_it it=listeners.find(&listener);
if (it==listeners.end()) throw_exception(ERR_NOT_SUBSCRIBED);
listeners.erase(it);
}
void Notifier::LockChildren() {
for(children_it it=children.begin();it!=children.end();++it) {
(*it)->Lock();
}
}
void Notifier::UnlockChildren() {
for(children_it it=children.begin();it!=children.end();++it) {
(*it)->Unlock();
}
}
void Notifier::NotifyAll() {
if (lock_level!=0) {
if (lock_level<0) throw_exception(ERR_BAD_LOCK_LEVEL_RO);
else throw_exception(ERR_BAD_LOCK_LEVEL);
}
lock_level=-1; // enter read only mode
for(listeners_it it=listeners.begin();it!=listeners.end();++it) {
(*it)->NotifyChange();
}
modified=false;
lock_level=0; // leave readonly mode
}
int Notifier::GetDeepLevel() const {
int deep=0;
for(children_cit it=children.begin();it!=children.end();++it) {
int d=(*it)->GetDeepLevel();
if (deep<d) deep=d;
}
return deep+1;
}
bool Notifier::IsDeepUnlocked() const {
for(children_cit it=children.begin();it!=children.end();++it) {
if (!(*it)->IsDeepUnlocked()) return false;
}
return true;
}
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, enji, Вы писали:
E>>гм. Чем убог function? о_О>тем что стандартная библиотека. хотелось native...
стандартная библиотека — это считай что native: компилятор может какие угодно хаки применять в реализации стандартной библиотеки.
В любом случае, даже если бы оно было встроено непосредственно в язык, что бы изменилось интерфейсно?
Это по сути указатель на функцию — так что, изобрести еще один указателеподобный значок, типа void (№)(int) ?
Так имхо, std::function< void(int) > читабельнее.
Здравствуйте, jazzer, Вы писали:
J>стандартная библиотека — это считай что native: компилятор может какие угодно хаки применять в реализации стандартной библиотеки.
будем реалистами, он не станет этого делать
J>В любом случае, даже если бы оно было встроено непосредственно в язык, что бы изменилось интерфейсно?
Например, вот придумал только сейчас:
delegate<signature> - оператор объявления типа делегата с сигнатурой signaturedelegate(function, оbject, (arg1, arg2, ... argN | _1, _2, ... _N) ) - оператор создания функционального объекта для делегата с сигнатурой function,
из функции function и (если function - член-функция) указателя на объект оbject//короче std::bind-like синтаксис, пусть только дедукцией занимается компилятор, а не костыли вида std::bind
Живой пример:
enum class EventType
{
Test = 0x0001,
};
struct Object
{
void OnEvent(EventType event)
{
//1st subscriber callback
}
};
void OnEvent(EventType event)
{
//2nd subscriber callback
}
int main()
{
Object object;
delegate<void(EventType event)> d = delegate(&Object::OnEvent, &object); //делегат d инициализируется первым подписчиком
d += delegate(OnEvent); //добавляется второй подписчик
d += [](EventType event) { /*3rd subscriber callback*/ }; //добавляется третий подписчик
d -= delegate(OnEvent); //второй, пожалуй, лишний
d(EventType::Test); //вызов подписчиков 1 и 3: метода Object::OnEvent объекта object и анонимной функции
//???
//ENJOY!!1
}
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
J>>стандартная библиотека — это считай что native: компилятор может какие угодно хаки применять в реализации стандартной библиотеки. о_О>будем реалистами, он не станет этого делать
это делается сплошь и рядом посредством intrinsic-ов.
почти вся std::type_traits — это просто обертка вокруг соответствующих intrinsic-ов, ее иначе полноценно не реализовать просто.
J>>В любом случае, даже если бы оно было встроено непосредственно в язык, что бы изменилось интерфейсно?
о_О>Например, вот придумал только сейчас:
смешались в кучу кони, люди, функции, слоты, сигналы, подписки, отписки...
Подписка/отписка/нотификация/трекинг — это существенно более сложные механизмы, чем просто универсальный указатель на функцию.
в бусте есть сигналы и сигналы2 — думаешь, почему? сигналы2 корректно поддерживают многопоточность, с соответствующими блокировками и прочими радостями. Я бы лично предпочел, чтоб это были разные механизмы, с разность степенью "тяжелости" реализации, потому что мне, например, далеко не всегда нужна многопоточность с соответствующими ей необходимыми приседаниями. (То же касается строк, кстати — нафига мне куча блокировок внутри, если я не собираюсь кидать строки между потоками?)
//капитанство поскипано
Что тебе конкретно не нравится? Что может быть несколько подписчиков? Так смысла в другой реализации нет. Якобы тяжесть этого механизма? Всё это цветочки, по сравнению с бустом, в котором потокобезопасные сигналы быстрее обычных (академики постарались).
Здравствуйте, jazzer, Вы писали:
J>эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов.
GUI
Здравствуйте, Kingofastellarwar, Вы писали:
K>да я в общем и не говорил что мне именно с++ нужен, мне нужен неуправляемый компилируемый в нативный код язык с современным синтаксисом, либами, метаданными и прочим
K>такого нет,
K>а мне нужен, потому что меня напрягает старческий маразм с++ и тормоза всего и вся в управляемых языках
В некоторых особенностях язык D выглядит более современным, чем C++
Здравствуйте, Mystic, Вы писали:
M>Здравствуйте, jazzer, Вы писали:
J>>эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов. M>GUI
Это плохой метод работы с GUI
Здравствуйте, о_О, Вы писали:
о_О>Здравствуйте, jazzer, Вы писали:
о_О>//капитанство поскипано о_О>Что тебе конкретно не нравится? Что может быть несколько подписчиков? Так смысла в другой реализации нет.
Это с чего это ты взял, что нет?
Мне вот лично сигналы с несколькими динамическими подписчиками подписчиками понадобились за все время ровно один раз, а все остальное время рулил простой как валенок boost::function.
о_О>Якобы тяжесть этого механизма?
Якобы? Поддержка многопоточности и подписки/отписки у нас теперь бесплатна?
о_О>Всё это цветочки, по сравнению с бустом, в котором потокобезопасные сигналы быстрее обычных (академики постарались).
Быстрее простого boost::function? (это я так напоминаю, что ты все хочешь в function засунуть.)
А то, что они быстрее первых сигналов — так там соображения обратной совместимости не позволили это дело улучшить, а иначе все сделали бы в рамках первых сигналов. Что никак не отменяет простого факта, что девайс с блокировками на борту в приципе не может быть быстрее такого же без каких-либо блокировок.
Здравствуйте, о_О, Вы писали:
о_О>Например, вот придумал только сейчас: о_О>
о_О>delegate<signature> - оператор объявления типа делегата с сигнатурой signature
о_О>delegate(function, оbject, (arg1, arg2, ... argN | _1, _2, ... _N) ) - оператор создания функционального объекта для делегата с сигнатурой function,
о_О>из функции function и (если function - член-функция) указателя на объект оbject
о_О>//короче std::bind-like синтаксис, пусть только дедукцией занимается компилятор, а не костыли вида std::bind
о_О>
Замени delegate на boost::signal2 + boost::bind и будет тебе счастье, даже синтаксис почти такой же, как у тебя в примере кода.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Mystic, Вы писали:
M>>Здравствуйте, jazzer, Вы писали:
J>>>эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов. M>>GUI J>Это плохой метод работы с GUI
Здравствуйте, Mystic, Вы писали:
J>>>>эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов. M>>>GUI J>>Это плохой метод работы с GUI
M>А как по мне, в Delphi и BCB он был очень неплох
Ага, пока не попытаешься повесить проверки типа один параметр должен быть больше другого и какой-нть пересчет по изменению.
Все такие вещи лучше иметь прописанными явно, а не быть закопанными где-то в сеттерах.
Здравствуйте, jazzer, Вы писали:
J>Мне вот лично сигналы с несколькими динамическими подписчиками подписчиками понадобились за все время ровно один раз, а все остальное время рулил простой как валенок boost::function.
это удобно в MVP, MVC
о_О>>Якобы тяжесть этого механизма? J>Якобы? Поддержка многопоточности и подписки/отписки у нас теперь бесплатна?
не обязательно их делать потокобезопасными. я бы сказал, что это лишнее
о_О>>Всё это цветочки, по сравнению с бустом, в котором потокобезопасные сигналы быстрее обычных (академики постарались). J>Быстрее простого boost::function? (это я так напоминаю, что ты все хочешь в function засунуть.)
я хочу отдельный встроенный тип delegate, например как в C#, дающий хороший байткод, и дедукцию компилятором (сотни ошибок bind при малейшей ошибки уже достали)
J>А то, что они быстрее первых сигналов — так там соображения обратной совместимости не позволили это дело улучшить, а иначе все сделали бы в рамках первых сигналов. Что никак не отменяет простого факта, что девайс с блокировками на борту в приципе не может быть быстрее такого же без каких-либо блокировок.
буст — не для эффективности, она для понтов (академики довольны). но кол-во абстракций и сущностей в библиотеке мне интересует в последнюю очередь.
Здравствуйте, о_О, Вы писали:
о_О>>>Всё это цветочки, по сравнению с бустом, в котором потокобезопасные сигналы быстрее обычных (академики постарались). J>>Быстрее простого boost::function? (это я так напоминаю, что ты все хочешь в function засунуть.) о_О>я хочу отдельный встроенный тип delegate, например как в C#, дающий хороший байткод, и дедукцию компилятором (сотни ошибок bind при малейшей ошибки уже достали)
Кстати насчет кода — мне кажется, жить стало бы сильно веселей, если бы можно было взять указатель на член как просто указатель на функцию (+ this). Т.е. был бы встроенный тип данных, который бы содержал собственно указатель на функцию и указатель на объект:
struct S
{
virtual void f()
};
struct C : S
{
void f();
};
typedef void (### PF)();
S* s = new C;
PF pf = &s->f; // тут генерируется код, который лезет в vtbl и находит C::f()
pf(); // в pf лежат два указателя - адрес C::f и s. В результате произойдет вызов s->C::f()
По идее для компилятора это особых сложностей не представляет, и вызов такой штуки будет эквивалентен вызову обычной функции по указателю. Даже если вызов функции-члена отличается от вызова обычной функции — компилятор может молча сделать переходник и сохранить указатель на него.
Так как этого нет, то приходится делать руками на уровне библиотеки — через шаблоны и виртуальные функции...
Здравствуйте, enji, Вы писали:
E>Кстати насчет кода — мне кажется, жить стало бы сильно веселей, если бы можно было взять указатель на член как просто указатель на функцию (+ this). Т.е. был бы встроенный тип данных, который бы содержал собственно указатель на функцию и указатель на объект
не сыпь мне соль на рану...
E>Кстати насчет кода — мне кажется, жить стало бы сильно веселей, если бы можно было взять указатель на член как просто указатель на функцию (+ this). Т.е. был бы встроенный тип данных, который бы содержал собственно указатель на функцию и указатель на объект
Ну, bind + mem_fun спасут отца русской демократии, нет?
Здравствуйте, enji, Вы писали:
E>мне кажется, жить стало бы сильно веселей, если бы можно было взять указатель на член как просто указатель на функцию (+ this). Т.е. был бы встроенный тип данных, который бы содержал собственно указатель на функцию и указатель на объект:
Здравствуйте, Kingofastellarwar, Вы писали:
K>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
Конечно, надо их ввести! А то как-то стыдно. Откроешь какой-нибудь файл на java или C# и пожалуйста — десяток полей, десяток геттеров, десяток сеттеров, сотня строк, выглядит солидно и убедительно. А на С++ позор один — несчастный struct на 10 строк и все. А уж если class, то в нем почти что и нет замечательных методов с телом return x; или this.x = x. Стыд и позор!
MZ>Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
Добавлю коротко и ясно — они есть в Visual C++ (__declspec(property)) , но никем не используются по той же самой причине.
Вот из MSDN
// declspec_property.cppstruct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
Здравствуйте, Pavel Dvorkin, Вы писали:
MZ>>... потому что нахрен они никому не нужны.
PD>Добавлю коротко и ясно — они есть в Visual C++ (__declspec(property)) , но никем не используются по той же самой причине.
Они не используются, потому что при переходе на другую платформу придётся всё переписывать
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, MasterZiv, Вы писали:
MZ>>Отвечу коротко и надеюсь ясно: потому что нахрен они никому не нужны.
PD>Добавлю коротко и ясно — они есть в Visual C++ (__declspec(property)) , но никем не используются по той же самой причине.
Здравствуйте, Abyx, Вы писали:
PD>>Добавлю коротко и ясно — они есть в Visual C++ (__declspec(property)) , но никем не используются по той же самой причине.
A>Говорите за себя. Я использую.
> PD>Добавлю коротко и ясно — они есть в Visual C++ (__declspec(property)) , но > никем не используются по той же самой причине. > > Говорите за себя. Я использую.
Значит, ты и есть тот самый Никто!
Люди, мы его нашли! Это он!
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Kingofastellarwar, Вы писали:
K>>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
PD>Конечно, надо их ввести! А то как-то стыдно. Откроешь какой-нибудь файл на java или C# и пожалуйста — десяток полей, десяток геттеров, десяток сеттеров, сотня строк, выглядит солидно и убедительно. А на С++ позор один — несчастный struct на 10 строк и все. А уж если class, то в нем почти что и нет замечательных методов с телом return x; или this.x = x. Стыд и позор!
как просто у вас, а если вам интерфес нужен а не класс?
class IService
{
public:
IMemeber Member;
};
class CService : public IService
{
CMember MemberImpl;
void InitMember()
{
Member = MemberImpl = new CMember(); // такое как? очень красиво когда у вас два мембера за одну и туже сущность отвечает?
}
// или мне нада писать этот приватный сеттер для своего же собственного мембера?private:
void SetMemeber(CMemeber * m)
{
Member = MemberImpl = m;
}
};
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, MasterZiv, Вы писали:
>> PD>Добавлю коротко и ясно — они есть в Visual C++ (__declspec(property)) , но >> никем не используются по той же самой причине. >> >> Говорите за себя. Я использую.
MZ>Значит, ты и есть тот самый Никто! MZ>Люди, мы его нашли! Это он!
Мне бы такое зрение. Увидеть Никого, на таком расстоянии, через километры IP-пакетов и десятки файрволлов...
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, Kingofastellarwar, Вы писали:
K>>почему ни в одном стандарте с++ до сих пор не предложили нормальные пропертя?
PD>Конечно, надо их ввести! А то как-то стыдно. Откроешь какой-нибудь файл на java или C# и пожалуйста — десяток полей, десяток геттеров, десяток сеттеров, сотня строк, выглядит солидно и убедительно. А на С++ позор один — несчастный struct на 10 строк и все. А уж если class, то в нем почти что и нет замечательных методов с телом return x; или this.x = x. Стыд и позор!
В C++ тоже длинные сопли с :: и < > очень радуют академический глаз.
Вообще то назначение пропертей не для большого кол-ва строк. А для удобства и сокращения записи. А то что их используют как попало это уж извиняйте.
— для скрытия реализации
class A {
List list; // потом могу переделать по другому и в других местах ничего не меняем.
public void Add(object a) { list.Add(); }
property int Count { get { return list.Count; } }
}
— Что бы не писать функции getX setX
struct SomeInterface {
virtual int getX()=0;
virtual int setX(int x)=0
};
— Для рефакторинга и отладки
было
class A {
public int X;
};
стало
class A {
int x;
public int X { get { return x; }
set {
if (value==100)
Debug.BreakPoint();
x=value;
}
}
}
— Можно использовать для валидации и оповещении об измении поля.
class A {
int x;
Validator validator;
Notifier notifier;
public int X { get { return x; }
set {
validator.validate(x);
if (x!=value) {
x=value;
notifier.notify_subscribers();
}
}
}
}
при этом из вне синтаксис как к обычному полю a.X=a.X+1;
и внутренние изменения переход от поля к гетерам и сетерам не приводит к изменению остального кода.
Здравствуйте, Vamp, Вы писали:
V>Такие языки уже есть. Называются Java, .NET. Превращать С++ в Джаву никакого смысла нет, да и стремно — можно нарваться на патентный иск со стороны Оракла.
Почему? Что-то могло бы быть и в С++.
Например, почему бы не иметь возможности работать с типами в СТ, как-то их декоспозицию осуществлять, менять и т. д.
Какие-то такие возможности даёт шаблонная магия, но очень бледные.
Потом рефлексия. Почему бе не дать, хотя бы в СТ возможность проитерировать все методы класса, например?
Вот скажем я хочу написать такой шаблон класса, который автоматом скопирует все публичные методы своегео параметра. Как мне это сделать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, icWasya, Вы писали:
W>Они не используются, потому что при переходе на другую платформу придётся всё переписывать
По идее проперти обычно продвигаются, как инструмент разработчика GUI.
А виндовый GUI на другой OS, всё равно переписывать...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Kingofastellarwar, Вы писали:
K>как просто у вас, а если вам интерфес нужен а не класс?
class IService
{
public:
virtual IMemeber* GetMember() = 0;
};
class CService : public IService
{
CMember MemberImpl;
virtual IMemeber* GetMember() { return &MemberImpl; }
};
Коротко, ясно и для интеропа с другими языками лучше приспособленно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, kov_serg, Вы писали:
_>- для скрытия реализации _>
_>class A {
_> List list; // потом могу переделать по другому и в других местах ничего не меняем.
_> public void Add(object a) { list.Add(); }
_> property int Count { get { return list.Count; } }
_>}
_>
Дык это,
_>class A {
List list; // потом могу переделать по другому и в других местах ничего не меняем.public:
void Add(object a) { list.Add(); }
int Count() const { return list.Count; }
};
_>- Что бы не писать функции getX setX _>
_>struct SomeInterface {
_> virtual int getX()=0;
_> virtual int setX(int x)=0
_>};
_>
Это я не понял, к чему и зачем.
_>было _>
_>class A {
_> public int X;
_>};
_>
Что за проблема?
Пишешь шаблон, типа
template<typename T> class debug_wrapper {
private:
T data;
protected:
T& Data() { return data; }
const T& Data() const { return data; }
public:
// тут кучка конструкторов, с вынесенным определением тела
// тут кучка операторов, с вынесенным определением телаoperator const T&() const { return Data(); }
operator T&() { return Data(); }
};
Вклюяаешь это в свои любимые отладочные тузы. И потом пишешь что-то типа:
class A {
public:
struct xxx_prop : debug_wrapper<int> {
void operator = ( int newValue )
{
this->Data() = newValue;
}
} X;
};
А если немного больше поработать, то можно сделать так, что можно будет написать таким образом:
_>class A {
_> int x;
_> public int X { get { return x; }
_> set {
_> if (value==100)
_> Debug.BreakPoint();
_> x=value;
_> }
_> }
_>}
_>
А тут вообще не факт, что какой-то клиентский код не нагнётся.
_>- Можно использовать для валидации и оповещении об измении поля. _>
_>class A {
_> int x;
_> Validator validator;
_> Notifier notifier;
_> public int X { get { return x; }
_> set {
_> validator.validate(x);
_> if (x!=value) {
_> x=value;
_> notifier.notify_subscribers();
_> }
_> }
_> }
_>}
_>
Мульку с шаблоном можно точно так же.
_>при этом из вне синтаксис как к обычному полю a.X=a.X+1;
Только это вот и плохо.
Совсем нет никакого желания, добавить в язчк такую граблю, что a.X++ может без объявления войны превратиться в какое-то чудовище... _>и внутренние изменения переход от поля к гетерам и сетерам не приводит к изменению остального кода.
Это неправда.
Вот представь себе, например, что надо куда-то отдать int* для заполнения
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Коротко, ясно и для интеропа с другими языками лучше приспособленно...
вот так обычно в с++ так и заканчиваются решения простых задач: изврат и разведение рук
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Kingofastellarwar, Вы писали:
K>>>как просто у вас, а если вам интерфес нужен а не класс?
E>>[ccode] E>>class IService E>>{ E>>public: E>> virtual IMemeber* GetMember() = 0; E>>};
K>вот так обычно в с++ так и заканчиваются решения простых задач: изврат и разведение рук
В чём изврат?
В С++ это стандартный способ интерфейса к аггрегированному объекту...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Например, почему бы не иметь возможности работать с типами в СТ, как-то их декоспозицию осуществлять, менять и т. д. E>Какие-то такие возможности даёт шаблонная магия, но очень бледные.
Я с этим я, кстати, не спорю. Например, я в упор не понимаю, почему превратить тип в const и получить ссылку на него можно с помощью встроенных средств языка, а наоборот — только путем шаблонов и их специализации. А это плохо по целому ряду причин, включая отсутствие нормальной диагностики ошибок.
Пример — я хочу объявить шаблонную функцию, принимающую аргумент исключительно по неконстантной ссылке — потому что внутри я буду его менять.
Попытка:
template <class T>
void n1(T& t) {
++t;
}
И не дай бог кто-то вызовет эту функцию с константным аргументом, например:
const int i = 10;
n1(i)
Ошибка отрепортится в недрах n1, со всем счастием репортов из шаблонов.
А мне нужно, чтобы я мог написать что-то вроде n1(non_const T& ) — и компилятор четко сказал, что тип требуется неконстантный. Я многого хочу?
E>Потом рефлексия. Почему бе не дать, хотя бы в СТ возможность проитерировать все методы класса, например?
Теоретически да. Практическая польза невелика в связи со всяким увлекательным наследованием.
Здравствуйте, Vamp, Вы писали:
E>>Потом рефлексия. Почему бе не дать, хотя бы в СТ возможность проитерировать все методы класса, например? V>Теоретически да. Практическая польза невелика в связи со всяким увлекательным наследованием.
Ну вот представь себе, что был бы какой-то механизм миксинов.
Скажем, такой хитрый шаблон, который всегда применяеся к MDT, как-то перебирает его интерфейс и модифицирует его.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
V>Ошибка отрепортится в недрах n1, со всем счастием репортов из шаблонов. V>А мне нужно, чтобы я мог написать что-то вроде n1(non_const T& ) — и компилятор четко сказал, что тип требуется неконстантный. Я многого хочу?
Ну в C++11 вроде выдали костыли для этого (type traits), в бусте и так давно были.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Ops, Вы писали:
Ops>Ну в C++11 вроде выдали костыли для этого (type traits), в бусте и так давно были.
Криво всё это и сложно.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
V>Я с этим я, кстати, не спорю. Например, я в упор не понимаю, почему превратить тип в const и получить ссылку на него можно с помощью встроенных средств языка, а наоборот — только путем шаблонов и их специализации. А это плохо по целому ряду причин, включая отсутствие нормальной диагностики ошибок. V>Пример — я хочу объявить шаблонную функцию, принимающую аргумент исключительно по неконстантной ссылке — потому что внутри я буду его менять.
Всё не совсем так уж плохо.
V>И не дай бог кто-то вызовет эту функцию с константным аргументом, например:
и всё будет хорошо, но всё равно геморрно так писать.
V>
V>const int i = 10;
V>n1(i)
V>
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
_>>- Что бы не писать функции getX setX _>>
_>>struct SomeInterface {
_>> virtual int getX()=0;
_>> virtual int setX(int x)=0
_>>};
_>>
E>Это я не понял, к чему и зачем.
что бы запись была более короткой
int X { get; set; }
E>Что за проблема?
точно что за проблема есть же макроассемблер.
компилятор должен упрощать написание кода, а не наоборот.
я всего лишь хочу что бы простые вещи записывались просто.
E>Пишешь шаблон, типа
template<typename T> class debug_wrapper {
E>private:
E> T data;
E>protected:
E> T& Data() { return data; }
E> const T& Data() const { return data; }
E>public:
E> // тут кучка конструкторов, с вынесенным определением тела
E> // тут кучка операторов, с вынесенным определением тела
E> operator const T&() const { return Data(); }
E> operator T&() { return Data(); }
E>};
главная проблема очень простая — я не могу достать класс родитель из этого wrapper-а
мне универсальность не нужна. просто под конкретную задачу написано.
... _>>стало _>>
_>>class A {
_>> int x;
_>> public int X { get { return x; }
_>> set {
_>> if (value==100)
_>> Debug.BreakPoint();
_>> x=value;
_>> }
_>> }
_>>}
_>>
E>А тут вообще не факт, что какой-то клиентский код не нагнётся.
не нагнётся.
_>>- Можно использовать для валидации и оповещении об измении поля. _>>
_>>class A {
_>> int x;
_>> Validator validator;
_>> Notifier notifier;
_>> public int X { get { return x; }
_>> set {
_>> validator.validate(x);
_>> if (x!=value) {
_>> x=value;
_>> notifier.notify_subscribers();
_>> }
_>> }
_>> }
_>>}
_>>
E>Мульку с шаблоном можно точно так же.
и как?
_>>при этом из вне синтаксис как к обычному полю a.X=a.X+1; E>Только это вот и плохо. E>Совсем нет никакого желания, добавить в язык такую граблю, что a.X++ может без объявления войны превратиться в какое-то чудовище...
любой инструмент можно использовать не по назначению.
поэтому мне больше всего нравится связка C + lua. низкоуровневый язык без заморочек + просто динамический легко расширяемый язык, который позволяет описывать всякую ерунду (которой обычно много во всяких ui), коротко и ясно. при этом эта ерунда не требует высокого быстродействия.
Оба языка просто портируются, имеют низкий порог вхождения.
_>>и внутренние изменения переход от поля к гетерам и сетерам не приводит к изменению остального кода. E>Это неправда. E>Вот представь себе, например, что надо куда-то отдать int* для заполнения
легко представляю. но это всего лишь особенность языка. да и потом там где используются пропертя указатели на них нафиг не нужны.
замена int на хитрую структуру тоже на поведётся на int*.
Здравствуйте, kov_serg, Вы писали:
_>что бы запись была более короткой _>
_>int X { get; set; }
_>
Запись
struct XXX {
int X;
};
ещё короче...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, kov_serg, Вы писали:
E>>Что за проблема? _>точно что за проблема есть же макроассемблер. _>компилятор должен упрощать написание кода, а не наоборот. _>я всего лишь хочу что бы простые вещи записывались просто.
IMHO, пропертя -- это не просто, а наоборот, оч. сложно.
_>главная проблема очень простая — я не могу достать класс родитель из этого wrapper-а
_>а для каждого поля делать указатель накладно, и неудобно инициализировать.
А зачем он нужен?
Ты привёл несколько примеров использования пропертей, там нигде аггрегирующийй обект нужен не был...
_>мне универсальность не нужна. просто под конкретную задачу написано.
IMHO, просто не надо пропети под С++ использовать. Идея сама по себе против шерсти.
Надо брать нужные юз-кейсы и смотерть, как удобно их сделать другими средствами.
Хотя я согласен, что в С++ можно было бы добавить механизм, который бы позволял из поля найти this объемлющего объекта, но тогда полю пришлось бы иметь уникальный тип. Ну да и фиг бы с ним.
E>>А тут вообще не факт, что какой-то клиентский код не нагнётся. _>не нагнётся.
Откуда следует, что не нагнётся?
E>>Мульку с шаблоном можно точно так же. _>и как?
Подписываешь в конструкторе объекта агрегатора на уведомлени от полей того, кого надо...
E>>Вот представь себе, например, что надо куда-то отдать int* для заполнения _>легко представляю. но это всего лишь особенность языка. да и потом там где используются пропертя указатели на них нафиг не нужны. _>замена int на хитрую структуру тоже на поведётся на int*.
Да. Я вообще считаю подход с пропертями тухлым. Архитектурной ошибкой.
Правила поведения системы, вместо того, что бы быть где-то декларативно выписанными, размазываются по каким-то левым сеттерам и геттерам.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Kingofastellarwar, Вы писали:
E>>class CService : public IService E>>{ E>> CMember MemberImpl; E>> virtual IMemeber* GetMember() { return &MemberImpl; } E>>};[/ccode] E>>Коротко, ясно и для интеропа с другими языками лучше приспособленно...
K>вот так обычно в с++ так и заканчиваются решения простых задач: изврат и разведение рук
Чувак, другой язык это не другой синтаксический сахарок но и другая парадигма.
Здравствуйте, johny5, Вы писали:
J>Чувак, другой язык это не другой синтаксический сахарок но и другая парадигма.
с такими фразами лучше в политику, "парадигмой" я могу оправдать всё что угодно и где угодно
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
Здравствуйте, Erop, Вы писали:
E>Хотя я согласен, что в С++ можно было бы добавить механизм, который бы позволял из поля найти this объемлющего объекта, но тогда полю пришлось бы иметь уникальный тип. Ну да и фиг бы с ним.
Именно так я накидал PROPERTY макро:
#define PROPERTY(PropertyName, OwnerType_, Type, InternalType, GetterName, SetterName) \
template<typename OwnerType>
struct Property##PropertyName : public PropertyValueHolder__<InternalType>
....
... //указатель на родительский класс получается вот такconst OwnerType* get_owner_this() const
{
return (const OwnerType*)(((const char*)this) - OFFSETOF(OwnerType, OwnerType::PropertyName));
}
.. // класс с уникальным именем
Property##PropertyName <OwnerType_> PropertyName;
и с помощью трюка что шаблонные функции инстанциируются только в месте использования, вполне легально было заюзать OFFSETOF на ещё не доопределённый класс.
Замечательно работало, правда использовал лишь единожды да и помоему позднее таки выкинул.
Если нужно, могу впостить код целиком.
Здравствуйте, Kingofastellarwar, Вы писали:
K>с такими фразами лучше в политику, "парадигмой" я могу оправдать всё что угодно и где угодно
Ты опять не понимаешь, языки это не синтаксические сахарки к одному и тому же. Вот ты хочешь от С++ то-же, что сделано в С# но только чтобы "быстрее". Разве ты сам не видишь тут противоречия?
С++ проектировался (парадигма была такая), чтобы быть быстрее.
С# проектировался, чтобы мм.. быть доступнее начинающим.
Вот вы даже в оригинальном посте поленились указатели расставить, видно что внимания к этому вопросу (принципам программирования на С++) совсем нет, нуно просто склепать. Я вам предложу вариант, именно то что вы хотели — без виртуального вызова:
class IService
{
public:
IMemeber* const Member;
protected:
IService(IMember* m) : Member(m) {}
};
class CService : public IService
{
CMemberImpl member;
public:
CService() : IService(&member)
{}
}
но это лютый изврат. Вариант Егора лучше — он понятнее (в парадигме), так обычно спрашивают доп. интерфейс у объекта.
Можно ещё поплясать на множественном наследовании, отнаследовать несколько интерфейсов и спрашивать их через dynamic_cast<>
class IService
{
virtual something_else...
};
class CService : public IService, CMemberImpl
{
}
либо написать свою реализацию virtual QueryInterface(enum.. );, либо инкапсулировать интерфейсы друг в друга.
Вообще имхо подобная проблема возникает редко, нужно бы посмотреть под капот, откуда он такой возникает и избавиться от него. У меня есть некие преположения почему подобные извраты вдруг потребовались...
Здравствуйте, johny5, Вы писали:
J>Здравствуйте, Kingofastellarwar, Вы писали:
K>>с такими фразами лучше в политику, "парадигмой" я могу оправдать всё что угодно и где угодно
J>Ты опять не понимаешь, языки это не синтаксические сахарки к одному и тому же. Вот ты хочешь от С++ то-же, что сделано в С# но только чтобы "быстрее". Разве ты сам не видишь тут противоречия?
J>С++ проектировался (парадигма была такая), чтобы быть быстрее. J>С# проектировался, чтобы мм.. быть доступнее начинающим.
J>Вот вы даже в оригинальном посте поленились указатели расставить, видно что внимания к этому вопросу (принципам программирования на С++) совсем нет, нуно просто склепать. Я вам предложу вариант, именно то что вы хотели — без виртуального вызова:
J>
J>но это лютый изврат. Вариант Егора лучше — он понятнее (в парадигме), так обычно спрашивают доп. интерфейс у объекта.
он не прокатит в куче случаев, например если у нас
CMemberImpl * member;
а не
CMemberImpl member;
придется писать
IMemeber** const Member;
а это порно
Я изъездил эту страну вдоль и поперек, общался с умнейшими людьми и я могу вам ручаться в том, что обработка данных является лишь причудой, мода на которую продержится не более года. (с) Эксперт, авторитет и профессионал из 1957 г.
K>он не прокатит в куче случаев, например если у нас
K>CMemberImpl * member; K>а не K>CMemberImpl member;
K>придется писать K> IMemeber** const Member; K>а это порно
Ну если у вас меняется имплементация IMember в рантайме, тогда вариант Егора тут выглядит чище, хоть он и тяжелее из-за виртуального вызова. Можно и было бы просто сбросить константность указателя Member в IService и менять его вместе со сменой имплементации IMember*, избегая двойного указателя.
Только уже опасно, т.к. клиент подобного интерфейса может скэшировать старый указатель. Я бы тогда лучше инкапсулировал IMember интерфейс в IService, чтобы огородить клиента от подобных проблем.
Здравствуйте, johny5, Вы писали:
J>Замечательно работало, правда использовал лишь единожды да и помоему позднее таки выкинул. J>Если нужно, могу впостить код целиком.
UB на UB + виртуальная база всё нагнёт...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, johny5, Вы писали:
J>>Замечательно работало, правда использовал лишь единожды да и помоему позднее таки выкинул. J>>Если нужно, могу впостить код целиком.
E>UB на UB + виртуальная база всё нагнёт...
UB там нет, разве что используется "фича" MSVC собственно компилять шаблон в месте использования.
А виртуальная база.. наследование тут никак не касается смещений к полям в структуре, они фиксированы относительно владеющего пропертью класса.
Здравствуйте, johny5, Вы писали:
J>UB там нет, разве что используется "фича" MSVC собственно компилять шаблон в месте использования. J>А виртуальная база.. наследование тут никак не касается смещений к полям в структуре, они фиксированы относительно владеющего пропертью класса.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, johny5, Вы писали:
J>А виртуальная база.. наследование тут никак не касается смещений к полям в структуре, они фиксированы относительно владеющего пропертью класса.
Что даёт такие гарантии?
Я понимаю, что если уж надо выкручиваться, то приходится хаккать. Но это именно хакки, а не промышленное решение. Другое дело, если бы такой сервис можно было бы обеспечить на уовне языка, так же, как и указатели на члены, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, johny5, Вы писали:
J>>А виртуальная база.. наследование тут никак не касается смещений к полям в структуре, они фиксированы относительно владеющего пропертью класса.
E>Что даёт такие гарантии?
Эм, что поля в классе не скачут с места на место?
E>Я понимаю, что если уж надо выкручиваться, то приходится хаккать. Но это именно хакки, а не промышленное решение. Другое дело, если бы такой сервис можно было бы обеспечить на уовне языка, так же, как и указатели на члены, например.
Я бы не сказал что моя обёртка такие уж "хаки", нормальная типобезопасная имплементация, пусть кривоват синтаксис но если надо... Плюс, есть же __declspec( property .. пусть даже непортируемое.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, johny5, Вы писали:
J>>UB там нет, разве что используется "фича" MSVC собственно компилять шаблон в месте использования. J>>А виртуальная база.. наследование тут никак не касается смещений к полям в структуре, они фиксированы относительно владеющего пропертью класса.
E>
По стандарту, строго говоря, да, делать какую то арифметику с this нехорошо. Но это UB для абстрактного компилятора в вакууме. Практически это 100% стабильно работает к примеру MSVC (ибо целочисленная арифметика с указателями даёт желаемое). И я думаю заведётся под все остальные среды исполнения. Сейчас мне в голову даже не приходит что может помешать подобной арифметике работать неверно.
Здравствуйте, johny5, Вы писали:
E>>Что даёт такие гарантии? J>Эм, что поля в классе не скачут с места на место?
Что смещение от this не изменится ни в каком MDT...
J>Я бы не сказал что моя обёртка такие уж "хаки", нормальная типобезопасная имплементация, пусть кривоват синтаксис но если надо... Плюс, есть же __declspec( property .. пусть даже непортируемое.
Ну да. Беда только в том, что проперти в С++ вообще криво смотрятся. И вообще это всё в целом криво.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, johny5, Вы писали:
J>По стандарту, строго говоря, да, делать какую то арифметику с this нехорошо. Но это UB для абстрактного компилятора в вакууме. Практически это 100% стабильно работает к примеру MSVC (ибо целочисленная арифметика с указателями даёт желаемое). И я думаю заведётся под все остальные среды исполнения. Сейчас мне в голову даже не приходит что может помешать подобной арифметике работать неверно.
Строго говоря уже OFFSETOF -- MS-spec...
И в MSDN'е про него вроде писали, что тока к POD применять мона...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, johny5, Вы писали:
J>>По стандарту, строго говоря, да, делать какую то арифметику с this нехорошо. Но это UB для абстрактного компилятора в вакууме. Практически это 100% стабильно работает к примеру MSVC (ибо целочисленная арифметика с указателями даёт желаемое). И я думаю заведётся под все остальные среды исполнения. Сейчас мне в голову даже не приходит что может помешать подобной арифметике работать неверно.
E>Строго говоря уже OFFSETOF -- MS-spec... E>И в MSDN'е про него вроде писали, что тока к POD применять мона...
Здравствуйте, johny5, Вы писали:
J>>>UB там нет, разве что используется "фича" MSVC собственно компилять шаблон в месте использования. J>>>А виртуальная база.. наследование тут никак не касается смещений к полям в структуре, они фиксированы относительно владеющего пропертью класса. E>>
E>>Это, по твоему, не UB? J>По стандарту, строго говоря, да, делать какую то арифметику с this нехорошо.
можно попробовать не использовать вообще offsetof, а вычислять смещение в runtime, один раз для каждой пары (класс,его property), то есть хранить такие смещения в глобальном объекте.
насколько это UB?
1) В С++ большие и маленькие буквы ОТЛИЧАЮТСЯ!!!
2)
Because of the extended functionality of structs in C++, in this language, the use of offsetof is restricted to "POD types", which for classes, more or less corresponds to the C concept of struct (although non-derived classes with only public non-virtual member functions and with no constructor and/or destructor would also qualify as POD).
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Piko, Вы писали:
E>>>Строго говоря уже OFFSETOF -- MS-spec... E>>>И в MSDN'е про него вроде писали, что тока к POD применять мона...
P>>http://www.cplusplus.com/reference/clibrary/cstddef/offsetof/
E>1) В С++ большие и маленькие буквы ОТЛИЧАЮТСЯ!!!
НИ ЕДИНОГО РАЗРЫВА!
да, я знаю
E>2)
Because of the extended functionality of structs in C++, in this language, the use of offsetof is restricted to "POD types", which for classes, more or less corresponds to the C concept of struct (although non-derived classes with only public non-virtual member functions and with no constructor and/or destructor would also qualify as POD).
Здравствуйте, Piko, Вы писали:
P>да, я видел, и?
И
1) OFFSETOF таки MS-специфик
2) Оба макроса требуют, что бы объемлющий класс был POD...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Piko, Вы писали:
P>можно попробовать не использовать вообще offsetof, а вычислять смещение в runtime, один раз для каждой пары (класс,его property), то есть хранить такие смещения в глобальном объекте. P>насколько это UB?
Гарантий тоже не будет.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Piko, Вы писали:
P>>можно попробовать не использовать вообще offsetof, а вычислять смещение в runtime, один раз для каждой пары (класс,его property), то есть хранить такие смещения в глобальном объекте. P>>насколько это UB? E>Гарантий тоже не будет.
То есть разница между двумя this, в случае когда один класс агрегирует другой, может быть разной для разных инстансов агрегирующего класса?
Здравствуйте, Piko, Вы писали:
P>То есть разница между двумя this, в случае когда один класс агрегирует другой, может быть разной для разных инстансов агрегирующего класса?
Оно, вроде как, может быть даже невычислимо, или неопределено...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>То есть разница между двумя this, в случае когда один класс агрегирует другой, может быть разной для разных инстансов агрегирующего класса? E>Оно, вроде как, может быть даже невычислимо, или неопределено...
что не вычислимо?
нельзя кастануть указатели разных типов к void* и вычислить разницу между ними?
Здравствуйте, Piko, Вы писали:
P>нельзя кастануть указатели разных типов к void* и вычислить разницу между ними?
А разве есть гарантии, что объект всегда будет лежать в одном сегменте памяти?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>нельзя кастануть указатели разных типов к void* и вычислить разницу между ними? E>А разве есть гарантии, что объект всегда будет лежать в одном сегменте памяти?
Здравствуйте, Piko, Вы писали:
P>>>нельзя кастануть указатели разных типов к void* и вычислить разницу между ними? E>>А разве есть гарантии, что объект всегда будет лежать в одном сегменте памяти?
P>вы о чём вообще?
Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>>>нельзя кастануть указатели разных типов к void* и вычислить разницу между ними? E>>>А разве есть гарантии, что объект всегда будет лежать в одном сегменте памяти? P>>вы о чём вообще? E>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти...
1. можете дать ссылку на стандарт? хотя бы приблизительно где об этом говорится, может ключевые слова.
я нашёл только три слова содержащие "seg", и все были SIGSEGV
2. По вашему мнению, объекты в памяти фрагментируются или нет? (это вопрос не про alignment)
Здравствуйте, Piko, Вы писали:
E>>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти...
P>1. можете дать ссылку на стандарт? хотя бы приблизительно где об этом говорится, может ключевые слова. P>я нашёл только три слова содержащие "seg", и все были SIGSEGV
Там не сегмент памяти, там все строже:
Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined.
5.7.6
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Здравствуйте, Erop, Вы писали:
E>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти...
но в винде ведь страничная организация памяти (как и сегментация, страничная организация памяти связана с преобразованием виртуального адреса (в данном случае линейного) в физический) так что можно вычетать любые два да и в линуксе тоже единственное кому стоит задуматься это тем кто пишет под "недооси" c cегментной организацией памяти (при сегментной организации у программы нет единого линейного адресного пространства. виртуальный адрес состоит из двух частей: селектора сегмента и смещения от начала сегмента) и да вот еще что а это правило относится к операциям < <= > => ???? потому что их я точно видел применными к абсолютно разным указателям там правда в скобках писалось что это нарушает стандарт но из за того что используется страничная организация памяти все будет хорошо работать "поддержка такого режима присутствует в большинстве 32битных и 64битных процессорах. такой режим является классическим для почти всех современных ОС, в том числе windows и семейства unix" (кстати эта библиотека GLIB)
вообщем если предположить что операторы == != можно применять только к указателям в один массив относится ли тоже самое и к < <= > => ???
E>>>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти... P>>1. можете дать ссылку на стандарт? хотя бы приблизительно где об этом говорится, может ключевые слова. P>>я нашёл только три слова содержащие "seg", и все были SIGSEGV Ops>Там не сегмент памяти, там все строже: Ops>
Ops>Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined.
5.7.6
ясно.
походу стандартно это можно реализовать только через явное хранение указателя на агрегирующий объект в каждом случае.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, johny5, Вы писали:
E>Что смещение от this не изменится ни в каком MDT...
MDT?
J>>Я бы не сказал что моя обёртка такие уж "хаки", нормальная типобезопасная имплементация, пусть кривоват синтаксис но если надо... Плюс, есть же __declspec( property .. пусть даже непортируемое.
E>Ну да. Беда только в том, что проперти в С++ вообще криво смотрятся. И вообще это всё в целом криво.
Это да, это был один из моментов в моём начальном посте. Несмотря на то что техническая возможность есть (я добавлял проперти в код, потом убрал) мне они оказались не нужны.
Одной из причин может быть то, что синтаксический сахарок достаточно жиденький: a = value вместо a(value); работая с переменной ты не ожидаешь каких то сайд-эффектов а тут как раз цель проперти — спрятать сайд эффекты под ликом переменной; ну и конечно достаточно сложно в плане перегрузки всех возможных операторов += и т.д...
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Piko, Вы писали:
P>>да, я видел, и? E>И E>2) Оба макроса требуют, что бы объемлющий класс был POD...
Имхо слишком сильное ограничение, похоже ребята хотят оградить от потенциальных измерений межклассовых смещений мемберов в дереве наследования, типа как от derived класса к мемберу в базовом. Опять же если мерять только внутри класса, то в какой иерархии наследования этого класса и POD он или не POD должно быть побоку. POD/или не POD мембер — sizeof & align в рантайме не меняются, отсюда и смещения — компайл-тайм константы.
Здравствуйте, johny5, Вы писали:
E>>Что смещение от this не изменится ни в каком MDT... J>MDT?
Most derived type, как подсказывает гугл.
В случае одной линии наследования подавляющее большинство реализаций расширяет классы добавлением в конец (и даже смещение до указателя на VMT может быть произвольным, в зависимости от того, какой класс в иерархии первым завёл хоть что-то виртуальное), но в случае множественного наследования уже не так.
В случае class C: A, B { ... } возникают интересные эффекты — если cc типа C, то (B*)cc и его static_cast аналог это уже указатель, не совпадающий с указателем на cc.
Ещё интереснее, если есть, например, общий класс A, его потомки B и C (причём в обоих A — virtual base) и D — производный от B и C. При этом тела объектов B и C будут содержать указатель на часть A, а не включать её напрямую как часть структуры, и доступ будет выполняться с резолвингом этого указателя; компилятор не имеет права это оптимизировать, кроме случая, когда он будет гарантированно уверен, что объект — типа B или C. В составном объекте D, будет одна копия A; где она будет находиться — дело компилятора, и из B и C будут указатели на неё, которые будут резолвиться при доступе к чему-то из A. Думаю, поэтому для этого механизма появилось слово virtual: неизвестно, кому принадлежит эта база.
Так что в общем случае всё настолько туманно, что нельзя надеяться...
Здравствуйте, jyuyjiyuijyu, Вы писали:
E>>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти... J>но в винде ведь страничная организация памяти (как и сегментация, страничная организация памяти связана с преобразованием виртуального адреса (в данном случае линейного) в физический) так что можно вычетать любые два да и в линуксе тоже единственное кому стоит задуматься это тем кто пишет под "недооси" c cегментной организацией памяти (при сегментной организации у программы нет единого линейного адресного пространства.
Вопрос не в формальной возможности вычитания, а в том, как потом использовать результат этого вычитания. Да, есть случаи, когда вычитание вообще не может быть однозначно определено, и хороший пример на это — сегментированная адресация в far модели (заметим, но не в huge). Или те архитектуры, которые слишком гарвардские и в которых указатели на разные типы данных, или на код и данные, могут совсем по-разному представляться (слышал такие — например, данные адресуются байтами, а код — 32-битными словами). В случае только виртуальной памяти таких проблем нет, ok. Но остаются другие — а что значит полученная разность между двумя областями, выделенными по неизвестному правилу неконтролируемым источником?
J>вообщем если предположить что операторы == != можно применять только к указателям в один массив относится ли тоже самое и к < <= > => ???
Даже если это не вызовет облома выполнения, смысла в них практически нет за пределами узких областей (таких, как реализация malloc).
Здравствуйте, netch80, Вы писали:
N>Здравствуйте, johny5, Вы писали:
E>>>Что смещение от this не изменится ни в каком MDT... J>>MDT? N>Most derived type, как подсказывает гугл.
Он мне подсказывал что то другое
N>Так что в общем случае всё настолько туманно, что нельзя надеяться...
Это всё понятно, токо я непрерывно намекаю на то что тут указатель нужно получить на владельца проперти, т.е. если ты описал проперти в классе А то и указатель this мы считаем c мембера класса А на this самого класса A. Весь этот туман просто идёт мимо в данном случае.
Здравствуйте, johny5, Вы писали:
J>Имхо слишком сильное ограничение, похоже ребята хотят оградить от потенциальных измерений межклассовых смещений мемберов в дереве наследования, типа как от derived класса к мемберу в базовом. Опять же если мерять только внутри класса, то в какой иерархии наследования этого класса и POD он или не POD должно быть побоку. POD/или не POD мембер — sizeof & align в рантайме не меняются, отсюда и смещения — компайл-тайм константы.
Когда кто-то считает себя умнее разработчиков компилятора, то это и называется, обычно UB...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, johny5, Вы писали:
E>>Что смещение от this не изменится ни в каком MDT... J>MDT?
J>Это да, это был один из моментов в моём начальном посте. Несмотря на то что техническая возможность есть (я добавлял проперти в код, потом убрал) мне они оказались не нужны.
+100500
Тем более, что у MS есть тот самый __declspec, для тех, кому надо убедиться в ненужности пропертей в С++
J>Одной из причин может быть то, что синтаксический сахарок достаточно жиденький: a = value вместо a(value); работая с переменной ты не ожидаешь каких то сайд-эффектов а тут как раз цель проперти — спрятать сайд эффекты под ликом переменной; ну и конечно достаточно сложно в плане перегрузки всех возможных операторов += и т.д...
И тут соглашусь.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, jyuyjiyuijyu, Вы писали:
J>вообщем если предположить что операторы == != можно применять только к указателям в один массив относится ли тоже самое и к < <= > => ???
Вот, как раз == != модно к любым, а — + < > -- только к указателям из одного блока памяти.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Piko, Вы писали:
P>походу стандартно это можно реализовать только через явное хранение указателя на агрегирующий объект в каждом случае.
Или через наследование.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, johny5, Вы писали:
J>Это всё понятно, токо я непрерывно намекаю на то что тут указатель нужно получить на владельца проперти, т.е. если ты описал проперти в классе А то и указатель this мы считаем c мембера класса А на this самого класса A. Весь этот туман просто идёт мимо в данном случае.
Так где гарантии, что "туман идёт мимо"?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>походу стандартно это можно реализовать только через явное хранение указателя на агрегирующий объект в каждом случае. E>Или через наследование.
это как? какой синтаксис получится?
"object.some_property=some_shit" ?
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, johny5, Вы писали:
J>>Это всё понятно, токо я непрерывно намекаю на то что тут указатель нужно получить на владельца проперти, т.е. если ты описал проперти в классе А то и указатель this мы считаем c мембера класса А на this самого класса A. Весь этот туман просто идёт мимо в данном случае.
E>Так где гарантии, что "туман идёт мимо"?
Хорошо, я принимаю твой выпод про разработчиков компиляторов, допустим они что то знают такое, чего я нет. Что то такое, что нарушает данную гарантию.
Давай порассуждаем, как иерархия наследования, в которой не-POD класс А участвует, может изменять смещения мемберов в классе А? Вообще, что может произойти с не-POD классом, чтобы трюк с OFFSETOF ломался (Причём именно в зависимости от: класс POD/не POD).
IRO>getMatrix пересчитает матрицу только в том случае если данные изменились, в противном вернет as is
Ага. А потом окажется, что "изменение данных" определено не верно, и данные не пересчитываются, возвращается старьё. Или наооборот — всё каждый раз пересчитывается.
Ненавижу не константные методы с названием "get..."
и надеяться на то, что оптимизатор рюхнёт, что для этой ссылки не нужно хранилище
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, johny5, Вы писали:
J>Давай порассуждаем, как иерархия наследования, в которой не-POD класс А участвует, может изменять смещения мемберов в классе А? Вообще, что может произойти с не-POD классом, чтобы трюк с OFFSETOF ломался (Причём именно в зависимости от: класс POD/не POD).
Лэйаут POD-типов описан в стандарте. Для остальных руки у компилятора развязаны...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>это как? какой синтаксис получится? P>>"object.some_property=some_shit" ? E>Да, почему нет? Просто класс описывать будет неудобно.
не, я спрашивал как именно такое реализуется наследованием.
Здравствуйте, Piko, Вы писали:
P>не, я спрашивал как именно такое реализуется наследованием.
Вопроса не понял. По графу наследования в С++ можно ходить вполне легально
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>не, я спрашивал как именно такое реализуется наследованием. E>Вопроса не понял. По графу наследования в С++ можно ходить вполне легально
Как вот это "object.some_property=some_shit" реализуется через наследование, да причём так, чтобы some_property имело доступ к object ?
Здравствуйте, Piko, Вы писали:
P>Как вот это "object.some_property=some_shit" реализуется через наследование, да причём так, чтобы some_property имело доступ к object ?
Через CRTP, например...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Piko, Вы писали:
P>Как вот это "object.some_property=some_shit" реализуется через наследование, да причём так, чтобы some_property имело доступ к object ?
template<typename THost, typename T, typename Tag = void>
class CppProperty {
T data;
protected:
CppProperty() : data( T() ) {}
// конструкторы копии дефолтныйvirtual void OnChange( CppProperty* = 0 ) { } // тут можно бы и избавиться от виртуальности.
// например, в методах CppProperty дёргать что-то вроде Host().OnChange(), но это менее банально.
THost& Host() { return *static_cast<THost*>( this ); }// тут мы требуем или дружбы или публичного наследованияconst THost& Host() const { return *static_cast<const THost*>( this ); }// тут тожеpublic:
CppProperty( const T& d ) : data( d ) {}
void operator = ( const CppProperty& d ) { data = d.data; OnChange(); }
void operator = ( const T& d ) { data = d; OnChange(); }
operator const T&() const { return data; }
CppProperty operator + ( const T& right ) const;
CppProperty operator + ( const CppProperty& right ) const;
CppProperty& operator += ( const T& right );
CppProperty& operator += ( const CppProperty& right );
// далее по аналогии для всех Срр операторов
};
template<typename THost, typename T, typename Tag>
inline CppProperty<THost, T, Tag> CppProperty<THost, T, Tag>::operator + ( const T& right ) const
{
return data + right;
}
template<typename THost, typename T, typename Tag>
CppProperty<THost, T, Tag> CppProperty<THost, T, Tag>::operator + ( const CppProperty<THost, T, Tag>& right ) const
{
return data + right.data;
}
template<typename THost, typename T, typename Tag>
inline CppProperty<THost, T, Tag> operator + ( const T& left, const CppProperty<THost, T, Tag>& right )
{
CppProperty<THost, T, Tag> res( left );
res += right;
return res;
}
template<typename THost, typename T, typename Tag>
inline CppProperty<THost, T, Tag>& CppProperty<THost, T, Tag>::operator += ( const T& right )
{
data += right;
OnChange();
return *this;
}
template<typename THost, typename T, typename Tag>
CppProperty<THost, T, Tag>& CppProperty<THost, T, Tag>::operator += ( const CppProperty<THost, T, Tag>& right )
{
data += right.data;
OnChange();
return *this;
}
// далее по аналогии
//------------------------------class MyClass : CppProperty<MyClass, int> {
public:
CppProperty<MyClass, int>& MyProp;
MyClass() : MyProp( *this ), count( 0 ) {}
MyClass( const MyClass& other ) : CppProperty<MyClass, int>( other ), MyProp( *this ), count( 0 ) {}
int ChangeCount() const { return count; }
protected:
int count;
virtual void OnChange( CppProperty<MyClass, int>* ) { count++; }
};
int foo_oo( int ii )
{
MyClass m;
m.MyProp = ii;
m.MyProp += 10;
m.MyProp += m.MyProp;
int count = m.ChangeCount();
return count;
}
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>Как вот это "object.some_property=some_shit" реализуется через наследование, да причём так, чтобы some_property имело доступ к object ? E>Через CRTP, например...
как СRTP поможет объекту some_property иметь доступ к объекту object?
Здравствуйте, Piko, Вы писали:
P>>>Как вот это "object.some_property=some_shit" реализуется через наследование, да причём так, чтобы some_property имело доступ к object ? E>>Через CRTP, например... P>как СRTP поможет объекту some_property иметь доступ к объекту object?
Здравствуйте, Erop, Вы писали:
P>>>это как? какой синтаксис получится? P>>>"object.some_property=some_shit" ? E>>Да, почему нет? Просто класс описывать будет неудобно. P>не, я спрашивал как именно такое реализуется наследованием.
class MyClass : AsProperty<int> {
вы в том примере это мест имели в виду когда говорили про наследование.
а я подумал может вы знаете способ через наследование, но без ссылок (чтобы без надежды на то, что ссылка соптимизируются).
в любом случае спасибо за пример
Здравствуйте, Mystic, Вы писали:
F>>Это случилось чуть раньше — в OLE/COM. F>>Там надо было. F>>А на них уже соорудили Дельфу.
M>Свойства были еще в Delphi первой версии (16-битная Windows), когда никакой другой языковой поддержки OLE/COM не было.
Св-ва в COM IDL были еще в 90-м году. Так что эту идею дельфя содрало у OLE и VB.
Здравствуйте, jazzer, Вы писали:
J>Ага, пока не попытаешься повесить проверки типа один параметр должен быть больше другого и какой-нть пересчет по изменению. J>Все такие вещи лучше иметь прописанными явно, а не быть закопанными где-то в сеттерах.
Дело не в этом, а в том, что какой-нить функциональный биндинг на ф-ию-сеттер более естественный, чем на переменную.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, jazzer, Вы писали:
J>>Ага, пока не попытаешься повесить проверки типа один параметр должен быть больше другого и какой-нть пересчет по изменению. J>>Все такие вещи лучше иметь прописанными явно, а не быть закопанными где-то в сеттерах.
V>Дело не в этом, а в том, что какой-нить функциональный биндинг на ф-ию-сеттер более естественный, чем на переменную.
Здравствуйте, Piko, Вы писали:
P>а я подумал может вы знаете способ через наследование, но без ссылок (чтобы без надежды на то, что ссылка соптимизируются).
Ну какая разница хранить указатель на хост или на свойство? Оверхед тот же, а хранить удобнее.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>а я подумал может вы знаете способ через наследование, но без ссылок (чтобы без надежды на то, что ссылка соптимизируются). E>Ну какая разница хранить указатель на хост или на свойство? Оверхед тот же, а хранить удобнее.
ну так тут пытались использовать offset of как раз для того, чтобы вообще не хранить указатель, без оверхеда
я подумал может у вас есть какое-то решение без оверхеда через "наследование", поэтому и спросил.
Здравствуйте, Piko, Вы писали:
P>ну так тут пытались использовать offset of как раз для того, чтобы вообще не хранить указатель, без оверхеда
Беда тут в том, что offsetof требует от объемлющего класса быть POD...
P>я подумал может у вас есть какое-то решение без оверхеда через "наследование", поэтому и спросил.
На самом деле, я думаю, что можно так всё устроить, что будет почти без оверхеда.
Но не понятно что за фичи требуются от "пропертей"
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
P>>ну так тут пытались использовать offset of как раз для того, чтобы вообще не хранить указатель, без оверхеда E>Беда тут в том, что offsetof требует от объемлющего класса быть POD...
так я понял это, поэтому и искал другие решения типа разницы двух this.
см. контекстом разговора
P>>я подумал может у вас есть какое-то решение без оверхеда через "наследование", поэтому и спросил. E>На самом деле, я думаю, что можно так всё устроить, что будет почти без оверхеда. E>Но не понятно что за фичи требуются от "пропертей"
я думаю основные фичи:
1. object.propery=someshit
2. someshit=object.property
3. воздействие на агрегирующий объект
1 и 2, достигаются тривиально и без оверхеда.
для 3 я пока не увидел решений без оверхеда.
может любители пропертей хотят ещё что-нибудь.
мне проперти особо не нужны, мне просто интересно как их можно реализовать на C++
Здравствуйте, Piko, Вы писали:
P>я думаю основные фичи: P>1. object.propery=someshit P>2. someshit=object.property P>3. воздействие на агрегирующий объект
P>1 и 2, достигаются тривиально и без оверхеда.
И без пропертей тоже
P>для 3 я пока не увидел решений без оверхеда.
мне так кажется, что в тех местах, где популярны проперти, оверхед не важен
Но, зато, важна возможность ничего не забыть сделать. Типа надо во всех конструкторах связать проперти с this, а это лишает идею посделднего смысла.
P>может любители пропертей хотят ещё что-нибудь. P>мне проперти особо не нужны, мне просто интересно как их можно реализовать на C++
OnChange типа поддержать?
Просто проперти -- они же по бедности в своё время возникли. В Срр хочется, что бы не толко гет и сет можно было дёрнуть, но и += там всякое, или Length() позвать...
Или профильтровать как-то методы оборачиваемого класса.
Вот, скажем, я делаю пропертю из std::vector<xxx> и хотел бы с этой пропертёй работать, как с массивом.
Или, хотя бы, примерно так...
А что касается обеспечения связи объемлющего объекта и вложенного, то там много решений возможно, в разной степени чистых.
например, можно взять какой-то нормальнй срр класс без пропертей. Пусть это будет class MyClass
объявить ему другом или вложенным класс MyClass::PropertiesPad.
Этот самый MyClass::PropertiesPad -- POD, и все его плоя -- шаблонные POD'ы без полей и конструкторов, которые в параметре шаблона получают указатель на поле MyClass, или указатель на сеттер и геттер.
Всё через прокчи и приведения типов транслирует в обращения к этой, указуемой переменной.
А адрес своего пала получают через offsetof.
Потом мы из MyClass и MyClass::PropertiesPad выводимся и получаем класс, в котором есть проперти.
При этом MyClass::PropertiesPad не содержит никаких атомарных полей, только пустые POD-стрыктуры.
По идее у компилятора большие возможности по оптимизации
Только не интересно это всё. Намного прикльнее таки с операторами разобраться.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>я думаю основные фичи: P>>1. object.propery=someshit P>>2. someshit=object.property P>>3. воздействие на агрегирующий объект
P>>1 и 2, достигаются тривиально и без оверхеда. E>И без пропертей тоже
да, само собой. value semantic рулит
P>>для 3 я пока не увидел решений без оверхеда. E>мне так кажется, что в тех местах, где популярны проперти, оверхед не важен
да, абсолютно согласен. мне просто интересны без-оверхедные решения
E>Но, зато, важна возможность ничего не забыть сделать. Типа надо во всех конструкторах связать проперти с this, а это лишает идею посделднего смысла.
можно использовать трюк с разным определением макросов (несколько разных определений одного и того же макроса. нужное определение используется по необходимости). это будет более single point of truth
E>А что касается обеспечения связи объемлющего объекта и вложенного, то там много решений возможно, в разной степени чистых.
E>например, можно взять какой-то нормальнй срр класс без пропертей. Пусть это будет class MyClass E>объявить ему другом или вложенным класс MyClass::PropertiesPad. E>Этот самый MyClass::PropertiesPad -- POD, и все его плоя -- шаблонные POD'ы без полей и конструкторов, которые в параметре шаблона получают указатель на поле MyClass, или указатель на сеттер и геттер. E>Всё через прокчи и приведения типов транслирует в обращения к этой, указуемой переменной. E>А адрес своего пала получают через offsetof. E>Потом мы из MyClass и MyClass::PropertiesPad выводимся и получаем класс, в котором есть проперти. E> ...
да, я думал об этом. раз offeset of только для pod — то можно использовать pod обвёртку.
Здравствуйте, Vamp, Вы писали:
J>>эти рекламируемые сайд-эффекты я видел полраза в жизни на тысячи раз, когда я видел пустые сеттеры-геттеры безо всяких сайд-эффектов. V>Я надеялся на твою поддержку!
Мою поддержку лови тоже.
По моему мнению просто ктото давно сказал, что все данные должны быть приватными — дальше остальные
подхватили — и понеслось ... в частности об этом же недавно читал в "священные знания С++"
... напоминает ситуацию с goto
Здравствуйте, carpenter, Вы писали:
C>По моему мнению просто ктото давно сказал, что все данные должны быть приватными — дальше остальные C>подхватили — и понеслось ... в частности об этом же недавно читал в "священные знания С++"
Вообще-то бывают же и просто структуры. std::pair, например...
Это какие-то фанаты безкомпромисные так сказали, наверное. Или в коде-стайле для каких-то совсем упоротых кодеров написали так, потому, что иначе никак
только не понятно при чём тут subj. Публичное у тебя поле или приватное, зачем ему быть пропертёй?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
E>>Кстати насчет кода — мне кажется, жить стало бы сильно веселей, если бы можно было взять указатель на член как просто указатель на функцию (+ this). Т.е. был бы встроенный тип данных, который бы содержал собственно указатель на функцию и указатель на объект V>Ну, bind + mem_fun спасут отца русской демократии, нет?
Спасут конечно, но это виртуальный вызов + вызов по указателю на функцию-член (вообще говоря тормозной — при этом надо обработать разные варианты виртуальности). Если бы компилер получил реальную функцию в момент взятия адреса, накладных расходов было бы как при обычном вызове по указателю
E>Спасут конечно, но это виртуальный вызов + вызов по указателю на функцию-член (вообще говоря тормозной — при этом надо обработать разные варианты виртуальности). Если бы компилер получил реальную функцию в момент взятия адреса, накладных расходов было бы как при обычном вызове по указателю
Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...
E>>Спасут конечно, но это виртуальный вызов + вызов по указателю на функцию-член (вообще говоря тормозной — при этом надо обработать разные варианты виртуальности). Если бы компилер получил реальную функцию в момент взятия адреса, накладных расходов было бы как при обычном вызове по указателю V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные? V>А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...
Здравствуйте, dilmah, Вы писали:
V>>В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. D>гм.. 10 микросекунд это *Огромное* время для вызова функции. Seek time многих жестких дисков меньше 10 микросекунд.
Ты шутишь. Seek time жёстких дисков — единицы *милли*секунд. То есть в 1000 раз больше. Вот открыл характеристики гигабайтников от Samsung и Seagate — 8.9мс и 9мс соответственно.
С другой стороны, оппонент тоже приводит странные цифры для сравнения: на актуальном сейчас железе, резолвинг одного значения из памяти, даже если она не загружена ни в какой из кэшей, это десятки *нано*секунд.
Здравствуйте, Abyx, Вы писали:
A>цена виртуального вызова — отсутствие инлайна.
Эта цена от степении косвенности и кратности диспечерезации не зависит
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Vamp, Вы писали:
V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
А почему именно такая цифра для сравнения?
Нет, оно, конечно, ещё меньше. В случае виртуального вызова нужно:
1. Один дополнительный лукап в память — если она даже не в L2; посмотрев таблицу скоростей всяких DDR пишем — 18.75нс (DDR3-1333, CL=9, восьмое слово), это один раз за ХЗ сколько. Размазывая по срабатываниям кэша, подсчитаем за 2 нс (среднепотолочно по больнице).
2. Неизвестная задержка на том, что не может быть сделан inline, если точно не известен класс, к которому относится объект (а точное знание в таком случае может быть только в конструкторе). Она состоит из цены двух перезагрузок конвейера команд (на входе в функцию и выходе), можно каждую из них посчитать за 10 тактов при условии, что код уже в кэше, при 3GHz процессоре это в сумме 6нс. Может, она тоже кэшируется, не знаю.
3. Совсем неизвестная задержка на том, что массовый inline может увеличить объём кода настолько, что станет меньше полезного влезать в L1.
В сумме получается меньше 10 *нано*секунд. Что, в принципе, хорошо. Но если это в цикле с малым телом, то становится безумно дорого.
V>А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...
+2. Мне кажется, что кроме особо хитрых случаев вроде тех же быстрых циклов оно не заметно.
V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
10 мкс — это на каком-нить 11МГц 8-битнике, на десктопе — меньше V>А вообще, конечно, остается только позавидовать людям, которые умеют писать настолько быстрые программы, что основным источником тормозов становится виртуальность вызовов...
Это накладные расходы, которых можно было бы избежать с поддержкой компилятора, причем как я понимаю, реализовать это в компиляторе — не сложно.
Понятно, что function+bind/лябмды — универсальнее, но в простых случаях было бы быстрее, проще и меньше кода
Здравствуйте, Vamp, Вы писали:
V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
Я делал.
Виртуальные вызовы определённо медленней чем обычные, особенно учитывая тот факт, что обычные вызовы могут инлайнится.
Но, когда необходимо делать некоторый runtime выбор с помощью virtual, не честно просто сравнивать обычные вызовы с virtual. В таких сравнениях обычным вызовам должен предшествовать некоторый runtime выбор: if, switch, и т.п.
Код теста: http://ideone.com/Tjzne
Я сравниваю несколько случаев, которые зависят от параметра "Types count":
* virtual func — "Type count" определяет количество derived классов. Сложность O(1).
* switch — "Type count" определяет количество веток case. Сложность в моём случае is O(1) (я проверял ассемблерный код, но это может зависеть от компилятора).
* if-else O(N) — "Type count" определяет количество веток. if-else здесь в виде цепочки, что приводит к сложности O(N).
* if-else O(log(N)) — "Type count" определяет количество веток. if-else рекурсивно вложены, формируя двоичный поиск со сложностью O(ln(n)).
* static polymorphism — "Type count" определяет количество классов policy/strategy. Порядок вызовов жёстко задан, что приводит к сложности O(1). Здесь фактически не используется runtime выбор, но всё же это очень показательно в плане того, что может случится с inlined вызовами.
Необходимо отметить, что в этих тестах вычисления настолько простые, что в случае static polymorphism они свёрнуты (после inlining) что привело к обратной зависимости времени на один вызов от "Type count".
Виртуальные вызовы в этом тесте сравнимы с главной альтернативой — switch.
Но, необходимо делать правильные выводы из результатов.
Например, используются циклы, поэтому vtables были в кэше. Но для очень random'ного execution path это не всегда верно. Также, варьируя количество параметров функций, можно получить другие результаты.
Также, вы можете получить совершенно другие результаты на другой платформе/компиляторе/настройках и т.п.
V>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные?
Если всё таки интересно "голое" сравнение virtual и обычного вызова, смотрите на графике результаты для "Types count"=1
V>>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные? EP>Если всё таки интересно "голое" сравнение virtual и обычного вызова, смотрите на графике результаты для "Types count"=1
точнее для чистоты эксперимента, нужно убрать BOOST_FORCEINLINE, и убедится что в ассеблерном коде стоит именно вызов а не inline.
Попробовал то же на: FreeBSD/i386, "Athlon(tm) 64 X2 Dual Core Processor 4800+" (2.5GHz), gcc 4.6.4.
Boost 1.45.0. Define IDEONE_DOT_COM не отключал, иначе не собирается. Компилятору сказано -O2.
EP>http://img856.imageshack.us/img856/6497/resultx64multipleseries.png EP>Результаты(для больших значений "Types count"): EP>static polymorphism < switch ~ virtual func < if-else O(log(N)) < if-else O(N)
График не рисовал. В числах у меня так:
* static — 0 (разве что при types count=1 там видно 1.22)
* switch — 26-29ns
* virtual — 27-30ns
* оба if-else дают примерно одинаково по ~36ns. Но их значения сильно шатаются (плюс-минус 3ns).
Как-то всё это странно. Получается, что неважно, какой метод отработки варианта используется — важно, что требуется делать выбор. Но почему?
Здравствуйте, netch80, Вы писали:
EP>>Код теста: http://ideone.com/Tjzne N>Попробовал то же на: FreeBSD/i386, "Athlon(tm) 64 X2 Dual Core Processor 4800+" (2.5GHz), gcc 4.6.4. N>Boost 1.45.0. Define IDEONE_DOT_COM не отключал, иначе не собирается. Компилятору сказано -O2.
Я использовал Boost 1.49 , скорей всего дело в этом.
EP>>http://img856.imageshack.us/img856/6497/resultx64multipleseries.png EP>>Результаты(для больших значений "Types count"): EP>>static polymorphism < switch ~ virtual func < if-else O(log(N)) < if-else O(N) N>График не рисовал. В числах у меня так: N>* static — 0 (разве что при types count=1 там видно 1.22) N>* switch — 26-29ns N>* virtual — 27-30ns N>* оба if-else дают примерно одинаково по ~36ns. Но их значения сильно шатаются (плюс-минус 3ns). N>Как-то всё это странно. Получается, что неважно, какой метод отработки варианта используется — важно, что требуется делать выбор. Но почему?
Я предполагаю, что это связанно с branch misprediction ( http://en.wikipedia.org/wiki/Branch_predictor ). Когда процессор не знает какая будет следующая инструкция — плохо во всех случаях.
В исходнике, в секции Settings, есть выбор для dispatch_base::type.
При dispatch_base_regular результат получается отличный от dispatch_base_shuffle_indexed : http://img195.imageshack.us/img195/6497/resultx64multipleseries.png
Результаты(для больших значений "Types count"):
static polymorphism < if-else O(log(N)) < switch < virtual func < if-else O(N)
Как вы видите, "if-else O(log(N))" даже быстрее чем "switch O(1)".
Я предполагаю, что это как раз из-за branch prediction.
В этом случае происходит регулярная итерация по "Types count" — 1,2,3..N.
Для такого регулярного паттерна, branch predictor работает прекрасно.
Например, давайте рассмотрим паттерн кода "if-else O(log(N))":
Как вы видите, для всех types<=N/2 выбор ветки в первой проверке один и тот же. Аналогичные выводы применимы рекурсивно ко вложенным проверкам. Значит это очень благоприятная ситуация для branch predicton.
Но для switch мой компилятор использовал indirect jump, что не привело к удачному branch prediction в большинстве случаев.
При dispatch_base_shuffle_indexed, такого регулярного паттерна нет, и branch predictor работает плохо во всех случаях.
Также важен ещё параметр "Types count" — для больших значений(при dispatch_base_shuffle_indexed) у virtual только один конкурент — switch (и то, когда реализован как O(1)).
Также важна реализация inderect call в конкретном процессоре.
V>>>Вот мне правда интересно, кто-то мерил сколько реально стоит виртуальный вызов в современных средах по сравнению с вызовом невиртуальным? В микросекундах? Я вот почему-то думаю, что виртуальный дороже невиртуального меньше чем на 10 микросекунд. Есть другие данные? EP>>Если всё таки интересно "голое" сравнение virtual и обычного вызова, смотрите на графике результаты для "Types count"=1 EP>точнее для чистоты эксперимента, нужно убрать BOOST_FORCEINLINE, и убедится что в ассеблерном коде стоит именно вызов а не inline.
ещё точнее нужно использовать dispatch_base_regular вместо dispatch_base_shuffle_indexed, чтобы не было постороннего кода в замерах.
Здравствуйте, Ops, Вы писали:
P>>>>что не вычислимо? P>>>>нельзя кастануть указатели разных типов к void* и вычислить разницу между ними? P>>>>в смысле char* E>>>Вообще-то в С++ можно вычетать не любые два указателя, а только два указателя внутрь одногои того же сегмента памяти... P>>1. можете дать ссылку на стандарт? хотя бы приблизительно где об этом говорится, может ключевые слова. P>>я нашёл только три слова содержащие "seg", и все были SIGSEGV Ops>Там не сегмент памяти, там все строже: Ops>
Ops>Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined.
5.7.6
Чтобы не было UB, можно использовать placement new: выделить char[sizeof(class_with_property)] и делать в него placement new для class_with_property.
После этого по-идеи вычитать указатели легально.