Здравствуйте, 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>
Принципиально — ничем. Только какое он имеет отношение к?
---
С уважением, Константин Сиваков