Здравствуйте, Evgeny.Panasyuk, Вы писали:
G>>А явно это как? Особенно интересно, как это "явно" будет выглядеть в обобщенном коде.
EP>Например simplify(v) или какой-нибудь унарный оператор ^^ v
Да я не про это. Кто будет "дергать за веревочку"? И главное — как он будет определять нужно ли "дергать"?
Есть
foo(x) -> void и
bar(x) -> variant[int, void].
if(x > 0) bar(x) else foo(x)
Нужно "дергать"?
if(x > 0) bar(x)
А теперь?
if(x > 0)
if(x > 10) x else foo(x)
А если так?
G>>А если автоматически, то получается тип Variant<Variant<T, void>, void> существовать не может? Я вас правильно понимаю?
EP>Хм, наверное да. Точнее существовать может, но до первого использования.
Плохо это. Потеряем возможность поймать "go wrong". Variant<Variant<T, void>, void> вполне может означать — что все ок... ну просто, например, вложеный if-c-else вычислился в void.
Привели к Variant<T, void> — и если "внутрях у неё" void — будем думать, что до вложенного if дело вообще не дошло.
Вывод, нужен таки maybe, а не суррогаты
G>>>>В нашем случае использовать if не получится...
EP>>>Почему?
G>>?! Очевидно, потому что if вернет нам новый variant. С которым "нужно что-то делать"
EP>Когда из if возвращается указатель на какую-нибудь абстрактную базу, при работе с ней придётся точно также выяснять — что же там внутри, и какой именно метод вызывать. Выбор-то никуда не исчезает
def a = if(x > 0) "a" else 1; // "абстракная база" в виде какого-нибудь IConvertable
def b = if(a is string) stringToX(a) else intToX(a); // Вполне конкретный X
В вашем случае:
b — это в лучшем случае variant[X]. Что дальше? Можно и по сложней примеры нарисовать — например, когда "база" таки нужна. Но, в вашем варианте получим очередной variant[T, U]
.
G>>Это пример из boost, в который вы мне тыкали, как в пример. И таки да... это называется, двойная диспетчеризация.
EP>Там одинарная диспетчеризация, а не двойная
Да же так
template <typename Visitor, typename Visitable>
inline
BOOST_VARIANT_AUX_APPLY_VISITOR_NON_CONST_RESULT_TYPE(Visitor)
apply_visitor(Visitor& visitor, Visitable& visitable)
{
return visitable.apply_visitor(visitor);
}
...
template <typename Visitor, typename VoidPtrCV, typename T>
inline
BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(typename Visitor::result_type)
visitation_impl_invoke_impl(
int, Visitor& visitor, VoidPtrCV storage, T*
, mpl::true_// never_uses_backup
)
{
return visitor.internal_visit(
cast_storage<T>(storage), 1L
);
}
Т.е. вот это все мне мерещится?!
Понимаете, то, что в данном случае диспетчеризация — скорее всего... этожплюсы, в конце концов — статическая (не виртуальная, если хотите) — ничего не меняет.
G>>Что мешает-то на лету "собрать" нужный тип (в вашем примере, это агрегат Widget и Gadget), реализующий _нужный_ интерфейс?!
EP>Пример сборки нужного типа в студию. Мне кажется это будет сложнее чем variant.
А в чем проблема? Я такой тип вам и в C# соберу "налету" — только в run-time. В чем проблемы то?! Нам же нужен только агригат (контейней, если хотите), который делегирует вызовы конкретного интерфейса, конкретному экземпляру.
В Nemerle — такой же фокус можно провернуть в compile-time. А сложность тут вообще не причем... этот код пишется ровно один раз.
EP>Тем что такой синтаксис можно получить на базе boost::variant
Синтаксис-то тут причем?! Скажите лучше во что это вычислится? В variant?
---
С уважением, Константин Сиваков