Re[11]: Что должен возвращать if?
От: gbear Россия  
Дата: 22.10.14 16:38
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Явно или автоматически: Variant<Variant<T, void>, void> -> Variant<T, void>


А явно это как? Особенно интересно, как это "явно" будет выглядеть в обобщенном коде.
А если автоматически, то получается тип Variant<Variant<T, void>, void> существовать не может? Я вас правильно понимаю?

G>>Почему только при присвоении?! Везде, где "по смыслу" должно быть T.


EP>Вот тут:

EP>
EP>auto foo()
EP>{
EP>    return (if(c) T{1} else T{2});
EP>}
EP>

EP>какой должен быть тип результата у foo?

Очевидно — variant.

EP>Ещё раз (третий?), речь об обобщённом коде:

EP>
EP>template<typename T, typename U>
EP>void bar()
EP>{
EP>    auto res = if(c) T{} else U{};
EP>    // use res as variant
EP>}
EP>

EP>Если делать здесь неявное преобразование variant[X] в X (в случае когда T == U), то этот код поломается, либо ему придётся вставлять дополнительные проверки.

Зачем здесь-то делать? Хотите работать с res как c variant'ом — ктож вам запретит Но если у вас есть, например, какая-нибудь ф-ция от X, то, согласитесь, удобней "уметь" в неё передавать variant[X] "as is", а не дергать какие-то unbox'ы.

G>>В нашем случае использовать if не получится...

EP>Почему?

?! Очевидно, потому что if вернет нам новый variant. С которым "нужно что-то делать"

G>>конечно, если вы не предлагаете "нафантазировать" для этого случая еще один — специальный — "if". Ну, который не будет вычисляться в variant .


EP>Зачем?


?! Вы серьезно не понимаете? ?! Очевидно, потому что "нормальный" if вернет нам новый variant. С которым "нужно что-то делать"


G>>А вариант с двойной диспетчеризацией — еще хуже. Надеюсь, вы сами это понимаете.


EP>Откуда двойная диспетчеризация-то?


boost::variant< int, std::string > v;

...

class times_two_visitor
    : public boost::static_visitor<>
{
public:

    void operator()(int & i) const
    {
        i *= 2;
    }

    void operator()(std::string & str) const
    {
        str += str;
    }

};

...

boost::apply_visitor( times_two_visitor(), v );


Это пример из boost, в который вы мне тыкали, как в пример. И таки да... это называется, двойная диспетчеризация.

G>>?! Вы вообще о чем? Как определить этот "метод"? Смысл использования variant'а — по вашей же логике — "впихнуть невпихуемое". Если мы подразумеваем общий интерфейс, то зачем variant-то?!

EP>Я уже приводил пример, придётся скопировать:
EP>
EP>Variant<Widget, Gadget> x, y;
EP>// ...
EP>apply(x, y, [](auto &x, auto &y)
EP>{
EP>    draw(x);
EP>    draw(y);
EP>    collide(x, y);
EP>});
EP>

EP>Здесь нет общего предка у Widget и Gadget (да и вообще у них нет ни одного метода), а интерфейс использования в данном случае у них одинаковый

Я где-то говорил за "общего предка"?! Процитирую себя

Если мы подразумеваем общий интерфейс, то зачем variant-то?!


Что мешает-то на лету "собрать" нужный тип (в вашем примере, это агрегат Widget и Gadget), реализующий _нужный_ интерфейс?!

G>>Проблему можно выразить так: Если результат if можно обработать только через PM, то зачем нам использовать if? Почему сразу не использовать PM?!

EP>Во-первых, не только через PM.

Возвращаемся к нашим баранам. Таки через visitor'ы предлагаете? Повторюсь — обработка через if даст вам на выходе опять variant. Т.е. получаем "один раз variant — всегда variant". Оно действительно надо?

EP>Во-вторых, претензия не понятна — в коде удобен if, получили из него variant, передали куда-то дальше, там обработали хоть PM'ом хоть ещё чем. В чём проблема-то?


"Хоть PM'ом" — означает "только PM'ом".

G>>Напоминаю, в сабже if — это "сахар" для PM.

EP>И что? Это мешает построить if возвращающий variant?

Да ничего не мешает. Вопрос не в этом. Вопрос в том, чего вы этим хотите добиться? Пресловутой "симметрии" с if-без-else, как вроде бы выяснили, добиться таким образом не получится. Так в чем смысл-то?

EP>>>Во-вторых — я же приводил уже примеры использования variant'а в C++ — нужен конкретный код?

G>>Не нужен. Яж вам говорю... чудес не бывает
G>>Одно дело, какой-нибудь условный:

G>>
G>>match (if (x > 0) getA() else getB())
G>>{
G>>  | y is A => handleA(y.PropertyOfA)
G>>  | y is B => handleB(y.MethodOfB())
G>>}
G>>

G>>А другое — предлагаемые вами "танцы на граблях" (с)

EP>Чем код выше, принципиально отличается от следующего:

EP>
EP>MATCH( IF(x>0) { return getA(); } ELSE { return getB(); } )
EP>    CASE(y IS A) { handleA(y.PropertyOfA); }
EP>    CASE(y IS B) { handleB(y.MethodOfB()); }
EP>;
EP>

EP>

Принципиально — ничем. Только какое он имеет отношение к?

---
С уважением, Константин Сиваков
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.