Re[9]: ternary для разных подклассов на стеке
От: uzhas Ниоткуда  
Дата: 22.12.16 13:04
Оценка: 3 (1)
Здравствуйте, night beast, Вы писали:

NB>спасиб. наверно, пока такие трюки опасно применять...


нашел эпичный срач на эту тему: http://stackoverflow.com/questions/35947296/about-binding-a-const-reference-to-a-sub-object-of-a-temporary
Re[10]: ternary для разных подклассов на стеке
От: PM  
Дата: 22.12.16 13:45
Оценка:
Здравствуйте, night beast, Вы писали:

NB>Здравствуйте, Кодт, Вы писали:


NB>>>раз пошла такая пьянка, то и по optional спрошу.

NB>>>какие-нибудь ограничения на размер или хранимые значения в нем есть?
NB>>>а то не очень бы хотелось чтобы он для int занимал в два раза больше памяти чем нужно...

К>>Ну а куда ты вынесешь один бит признака "есть данные — нет данных"?


NB>у себя в велосипеде я использую особые значения вроде INT_MIN (конкретная стратегия применят флаг или некоторое значение задается в треитсах)


Типа такого: https://github.com/akrzemi1/compact_optional ? Вроде бы требования довольно распространённые, реализация несложная. Странно, что в std::optional не включили traits. Похоже, просто не нашлось желающих сделать соответствующее предложение.
Re[11]: ternary для разных подклассов на стеке
От: night beast СССР  
Дата: 22.12.16 14:06
Оценка:
Здравствуйте, PM, Вы писали:

К>>>Ну а куда ты вынесешь один бит признака "есть данные — нет данных"?


NB>>у себя в велосипеде я использую особые значения вроде INT_MIN (конкретная стратегия применят флаг или некоторое значение задается в треитсах)


PM>Типа такого: https://github.com/akrzemi1/compact_optional ? Вроде бы требования довольно распространённые, реализация несложная.


реализация другая, но смысл такой.

PM>Странно, что в std::optional не включили traits. Похоже, просто не нашлось желающих сделать соответствующее предложение.


тут проблема в том что треитсы (или таги) придется или вторым шаблонным параметром передавать,
или вместо optional< int > использовать optional< some_strategy_tag<int> > (some_strategy_tag используется только для недефолтовых треитсов)
возможно решили что оно того не стоит.
Отредактировано 22.12.2016 14:07 night beast . Предыдущая версия .
Re[12]: ternary для разных подклассов на стеке
От: PM  
Дата: 22.12.16 18:58
Оценка:
Здравствуйте, night beast, Вы писали:

PM>>Странно, что в std::optional не включили traits. Похоже, просто не нашлось желающих сделать соответствующее предложение.


NB>тут проблема в том что треитсы (или таги) придется или вторым шаблонным параметром передавать,

NB>или вместо optional< int > использовать optional< some_strategy_tag<int> > (some_strategy_tag используется только для недефолтовых треитсов)
NB>возможно решили что оно того не стоит.

Насколько я понял из обсуждения https://groups.google.com/a/isocpp.org/forum/m/#!topic/std-proposals/46J1onhWJ-s/discussion дополнительная стратегия для optional может поменять его семантику, что привело бы к существенным изменениям в существующем std::optional, так что дальше обсуждения дело не пошло.
Re[13]: ternary для разных подклассов на стеке
От: night beast СССР  
Дата: 22.12.16 20:02
Оценка:
Здравствуйте, PM, Вы писали:

NB>>тут проблема в том что треитсы (или таги) придется или вторым шаблонным параметром передавать,

NB>>или вместо optional< int > использовать optional< some_strategy_tag<int> > (some_strategy_tag используется только для недефолтовых треитсов)
NB>>возможно решили что оно того не стоит.

PM>Насколько я понял из обсуждения https://groups.google.com/a/isocpp.org/forum/m/#!topic/std-proposals/46J1onhWJ-s/discussion дополнительная стратегия для optional может поменять его семантику, что привело бы к существенным изменениям в существующем std::optional, так что дальше обсуждения дело не пошло.


как я понял, предлагали еще в 12г (когда не было std::optional), но походу, забили на это дело ))
Re[3]: ternary для разных подклассов на стеке
От: Evgeny.Panasyuk Россия  
Дата: 22.12.16 20:41
Оценка:
Здравствуйте, tdiff, Вы писали:

EP>>Как вариант можно вот так:

EP>>
EP>>[&](base &&x)
EP>>{
EP>>    x.f();
EP>>}(true ? static_cast<base&&>(d1()) : static_cast<base&&>(d2()));
EP>>

T>Не совсем понимаю, в чём тут разница с
T>
T>base && x = (true ? static_cast<base&&>(d1()) : static_cast<base&&>(d2()));
T>x.f() ?
T>


Разница в том, что в варианте с вызовом лямбды (или даже простой функции) — это всё одно выражение (expression), и есть гарантия что временные объекты живут до конца выполнения выражения в котором были созданы.
Во втором же случае, потребовалась бы продление времени жизни временной переменной до конца scope — что в данном случае нетривиально, так как потребовало бы от компилятора запоминание того какого типа значение в итоге забиндилось, сколько оно занимает на стэке, и в конце scope в зависимости от варианта — d1 или d2 — вызывать правильный деструктор и правильно очищать стэк.
Re[4]: ternary для разных подклассов на стеке
От: tdiff  
Дата: 23.12.16 08:28
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Во втором же случае, потребовалась бы продление времени жизни временной переменной до конца scope


Спасибо за подробный ответ, но по-моему у нас есть гарантия, что const & / && — ссылки продлевают жизнь временным объектам.
Re[5]: ternary для разных подклассов на стеке
От: N. I.  
Дата: 23.12.16 08:28
Оценка: 2 (1)
tdiff:

NI>>Разница в том, что во втором случае к моменту вызова f ссылка x указывает на мёртвый объект.


T>Почему, если base&& должна продлевать время жизни temporary?


Всё дело в мутном понятии "temporary". Под ним подразумеваются сразу и временный объект и выражение, которое обозначает этот объект. Выражению, которое мы используем в качестве инициализатора ссылки на временный объект, недостаточно просто ссылаться на данный объект, чтоб его время жизни продлялось, — само выражение должно быть "temporary" (если б продление времени жизни временного объекта работало для любого выражения-инициализатора, то как минимум возникли бы очевидные сложности с проверкой, является ли объект временным).

Выражение является temporary только если в правилах для него явно указано, что оно temporary, либо если оно непосредственно создаёт и возвращает некий temporary object, либо если оно эквивалентно чему-то, что является temporary (если temporary обернуть в круглые скобки, то получившееся выражение тоже будет temporary). Разумеется, нормальной формализацией тут и не пахнет, и одно лишь чтение стандарта не приводит к пониманию что есть что; нужно просто знать, что стандартизаторы имели в виду.

T>У меня есть догадка, что происходит что-то вроде:

T>1. создаётся temporary d1() с типом d1&&

Выражения никогда не имеют ссылочный тип. Типом выражения d1() будет d1.

T>2. тип этого объекта конвертируется в base&&


Формально там prvalue типа d1 преобразуется к xvalue типа base. Исходное prvalue является temporary, а получившееся xvalue уже не является temporary (хотя оно тоже ссылается на временный объект).

T>3. результатом ternary является base&&, которая продлевает время жизни d1


Нет там никаких ссылок.

T>этой ссылкой инициализируется ссылка base&& x, которая почему-то уже не продлевает жизни d1


x инициализируется non-temporary выражением, поэтому продление не применяется.
Re: ternary для разных подклассов на стеке
От: Erop Россия  
Дата: 23.12.16 10:05
Оценка:
Здравствуйте, tdiff, Вы писали:

T>хочу, чтобы стек выглядел вот так:

T>[ссылка на объект ниже]
T>[d1 или d2]
T>и время жизни d1 или d2 совпадало с текущим скоупом.

Что мешает написать то, что ты хочешь, прямо?
struct base {
    virtual ~base() {}
    virtual void f() = 0;
};

struct d1 : base { long long x; void f() { x++; } };
struct d2 : base { static int x; void f() { x++; } };

class CBasePlaceholder {
public:
    CBasePlaceholder() : ptr(0) {}
    CBasePlaceholder(const CBasePlaceholder&) = delete;
    CBasePlaceholder(CBasePlaceholder&&) = delete;
    ~CBasePlaceholder() { Destroy(); }

    base* Ptr() const { return ptr; }
    base* operator ->() const { assert(ptr != 0); return ptr; }

    template<typename T> base* New() { Destroy(); return ::new(&bodyStart) T(); }

    void Destroy()
    {
        if (base* toDelete = ptr) {
            ptr = 0;
            toDelete->~base();
        }
    }
private:
    typedef double tAlignmentAs;
    enum {
        firstSize = sizeof(d1),
        secondSize = sizeof(d2),
        bufferSize = firstSize > secondSize ? firstSize : secondSize
    };
    tAlignmentAs bodyStart;
    char bodyRest[bufferSize - sizeof(tAlignmentAs)];
    base* ptr;

};

void foo(bool f)
{
    CBasePlaceholder t;
    base& rt = *(f ? t.New<d1>() : t.New<d2>());
    rt.f();
}


Шаблоны, вариадики и обработку случая, когда максимальный рзмер буфера меньше или равен sizeof(tAlignmentAs) добавить по вкусу

А вообще-то, писать так как тебе не хочется проще и понятнее всего
За одно ещё и от динамического полиморфизма избавишься
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: ternary для разных подклассов на стеке
От: N. I.  
Дата: 23.12.16 14:21
Оценка:
Erop:

E>Что мешает написать то, что ты хочешь, прямо?


Много букв и error prone, если не знать, как правильно создавать и удалять вручную объекты с правильным соблюдением всех па.

E>Шаблоны, вариадики и обработку случая, когда максимальный рзмер буфера меньше или равен sizeof(tAlignmentAs) добавить по вкусу


Если есть alignas/alignof, то лучше сразу использовать их: http://melpon.org/wandbox/permlink/sHVUIR2vV9aBtrUc

Другое дело, что вряд ли всё это вообще нужно. Обычно такие объекты или редко создаются или сами по себе настолько тяжелы, что подобная "оптимизация" реально ничего заметного не даст.
Re[5]: ternary для разных подклассов на стеке
От: Evgeny.Panasyuk Россия  
Дата: 23.12.16 14:52
Оценка: +1
Здравствуйте, tdiff, Вы писали:

EP>>Во втором же случае, потребовалась бы продление времени жизни временной переменной до конца scope

T>Спасибо за подробный ответ, но по-моему у нас есть гарантия, что const & / && — ссылки продлевают жизнь временным объектам.

Не во всех случаях.
Re[6]: ternary для разных подклассов на стеке
От: tdiff  
Дата: 23.12.16 14:54
Оценка:
Здравствуйте, N. I., Вы писали:

NI>Всё дело в мутном понятии "temporary". Под ним подразумеваются сразу и временный объект и выражение, которое обозначает этот объект. Выражению, которое мы используем в качестве инициализатора ссылки на временный объект, недостаточно просто ссылаться на данный объект, чтоб его время жизни продлялось, — само выражение должно быть "temporary" (если б продление времени жизни временного объекта работало для любого выражения-инициализатора, то как минимум возникли бы очевидные сложности с проверкой, является ли объект временным).

NI> ...
NI> Выражение является temporary только если в правилах для него явно указано, что оно temporary, либо если оно непосредственно создаёт и возвращает некий temporary object
NI> ...
NI>Формально там prvalue типа d1 преобразуется к xvalue типа base. Исходное prvalue является temporary, а получившееся xvalue уже не является temporary (хотя оно тоже ссылается на временный объект).
NI> ...
NI>x инициализируется non-temporary выражением, поэтому продление не применяется.

Спасибо за подробный ответ. Это действительно довольно мутно Например, почему "получившееся xvalue уже не является temporary"? Беглый поиск "temporary expression" по стандарту вообще находит только одно упоминание.
Re: ternary для разных подклассов на стеке
От: kov_serg Россия  
Дата: 23.12.16 14:56
Оценка:
Здравствуйте, tdiff, Вы писали:

T>Привет


T>Хочется в зависимости от условия создавать на стеке объекты разных подтипов одного общего класса, но пока не получается:

T>
T>class base { virtual void f() const = 0;};
T>class d1 : public base { void f() const override {...} };
T>class d2 : public base { void f() const override {...} };

T>const base& obj = true ? (const base&)d1() : d2();
T>obj.f();
T>

...
T>а создавать без повода объекты на хипе тоже как-то не круто.

А зачем тебе вообще объекты?
Re[7]: ternary для разных подклассов на стеке
От: N. I.  
Дата: 23.12.16 15:42
Оценка: 7 (2)
tdiff:

T>Например, почему "получившееся xvalue уже не является temporary"?


Потому что не указано, что оно temporary Вот, смотри:

__declspec(dllimport) X *dll_func(X &&, X *);

int main()
{
    auto &&x = static_cast<X &&>(*dll_func(X(), new X));
    ....
}

Теоретически dll_func может вернуть указатель на временный объект, созданный выражением X(), но она также может вернуть и что-нибудь иное — например, указатель на объект, созданный выражением new X. Как компилятор узнает, ссылается ли выражение static_cast<X &&>(*dll_func(X(), new X)) на временный объект? Очевидно, что для продления времени жизни временного объекта как минимум требуется какой-то признак того, что объект действительно является временным. Если объект берётся из какого-то выражения, то таким признаком служит принадлежность выражения к определённому виду. Если выражение к соответствующему виду не принадлежит, то время жизни объекта, на который оно ссылается, продляться не будет (независимо от того, является объект временным или нет).
Re[2]: ternary для разных подклассов на стеке
От: Evgeny.Panasyuk Россия  
Дата: 23.12.16 18:20
Оценка: +1 :)
Здравствуйте, Erop, Вы писали:

T>>хочу, чтобы стек выглядел вот так:

T>>[ссылка на объект ниже]
T>>[d1 или d2]
T>>и время жизни d1 или d2 совпадало с текущим скоупом.
E>Что мешает написать то, что ты хочешь, прямо?

Видимо желание узнать о готовом решении а-ля boost/std::variant превалирует над желанием лисапедить
Re[3]: ternary для разных подклассов на стеке
От: Erop Россия  
Дата: 23.12.16 19:32
Оценка:
Здравствуйте, N. I., Вы писали:

NI>Много букв и error prone, если не знать, как правильно создавать и удалять вручную объекты с правильным соблюдением всех па.

Конкретно этот трудно довольно неправильно использовать, если ещё и operator = удалить.

NI>Другое дело, что вряд ли всё это вообще нужно. Обычно такие объекты или редко создаются или сами по себе настолько тяжелы, что подобная "оптимизация" реально ничего заметного не даст.


Казалось бы, если тяжелы, то стека в два раза меньше съестся...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: ternary для разных подклассов на стеке
От: Erop Россия  
Дата: 23.12.16 19:35
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Видимо желание узнать о готовом решении а-ля boost/std::variant превалирует над желанием лисапедить


Я так понимаю, что всё это под флагом борьбы с оверхедом же?
Конечно подозрительная такая бескомпромиссная борьба, но фиг его знает-то, может людям реально надо...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: ternary для разных подклассов на стеке
От: tdiff  
Дата: 23.12.16 20:05
Оценка: :)
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, Evgeny.Panasyuk, Вы писали:


EP>>Видимо желание узнать о готовом решении а-ля boost/std::variant превалирует над желанием лисапедить


E>Я так понимаю, что всё это под флагом борьбы с оверхедом же?

E>Конечно подозрительная такая бескомпромиссная борьба, но фиг его знает-то, может людям реально надо...

Да нет, без флага. Из любопытства
Re[2]: ternary для разных подклассов на стеке
От: tdiff  
Дата: 23.12.16 20:07
Оценка:
Здравствуйте, kov_serg, Вы писали:

_>А зачем тебе вообще объекты?


Ну как обычно, ради состояния
Re[3]: ternary для разных подклассов на стеке
От: Erop Россия  
Дата: 23.12.16 20:28
Оценка:
Здравствуйте, tdiff, Вы писали:

T>Ну как обычно, ради состояния


А динамический полиморфизм для чего?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.