Вопрос по std::variant
От: pva  
Дата: 06.06.25 11:57
Оценка: 2 (1) +2
Привет,

воткнул тут с примером с cppref.
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
...
for (auto& v: vec) {
  std::visit(overloaded{
    [](auto arg) { std::cout << arg << ' '; },
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
  }, v);
}


А можно ли сделать подобное для бинарных операций?
using value_t = std::variant<int, long, double, std::string>;
...
// как должна выглядеть applyOp чтобы можно было записать?
value_t operator+(const value_t& l, const value_t& r) {
  return applyOp(l, r, overloaded {
    [](const auto& l, const auto& r) { return l + r; },
    [](const std::string& l, const auto& r) { return l + std::to_string(r); }
  });
}


p.s. Отвечу сам себе
value_t operator+(const value_t& l, const value_t& r) {
  return std::visit(overloaded {
    [](const auto& l, const auto& r) { return l + r; },
    [](const std::string& l, const auto& r) { return l + std::to_string(r); }
  }, l, r);
}
newbie
Отредактировано 06.06.2025 12:11 pva . Предыдущая версия .
Re: Вопрос по std::variant
От: Кодт Россия  
Дата: 06.06.25 23:21
Оценка: 2 (1)
va>А можно ли сделать подобное для бинарных операций?
pva>p.s. Отвечу сам себе

Помнится, год или два назад тут поднимали тему — как написать полиморфного посетителя такого же вида.
Там есть некоторые интересные моменты по диспетчеризации.

Можно
— неупорядоченные перегрузки, выбор компилятором наилучшей подходящей
— — если есть неоднозначность (выбор среди нескольких наилучших) — давать ошибку компиляции
— — раздавать приоритеты
— — подсовывать дефолтные обработчики
— двойная диспетчеризация, то есть, выбор наилучшей по первому аргументу, затем по второму...
— упорядоченные перегрузки, выбор первой подходящей в списке

Идиома с наследованием — это изящно, но она содержит подводную граблю, с наследованием от одинаковых типов. В случае уникальных лямбд это, конечно, не проблема.

для связности:

https://rsdn.org/forum/cpp/8497841.1
Автор: Chorkov
Дата: 04.04.23


https://rsdn.org/forum/cpp/8554157.1
Автор: Кодт
Дата: 30.06.23


вроде бы ещё раньше обсуждали эти темы, но я так не упомню
Перекуём баги на фичи!
Re[2]: Вопрос по std::variant
От: rg45 СССР  
Дата: 07.06.25 05:57
Оценка: 2 (1)
Здравствуйте, Кодт, Вы писали:

К>для связности:

К>https://rsdn.org/forum/cpp/8497841.1
Автор: Chorkov
Дата: 04.04.23


По прошествии времени смотрю на этот свой пост
Автор: rg45
Дата: 08.04.23
, как на вредный совет. Сейчас бы я сделал так:

template<class T> concept has_foo = requires (T t) { t.foo(0); };
template<class T> concept has_bar = requires (T t) { t.bar(""); };

....
visit(your_tuple,
  overloaded{
    [](has_foo auto&& t) { t.foo(123); },
    [](has_bar auto&& t) { t.bar("hello"); },
    [](auto&& t) { },  // без констрейнов имеет меньший приоритет, чем с констрейнами
  }
);


Ведь на концептах можно выстраивать иерархии типов не хуже, чем иерархии наследований классов (и даже лучше). И изящно использовать эту возможность в сочетании с overload resolution.

И std::decay_t здесь не нужен, если разобраться.

А вот, что имело бы смысл сделать (не в этом конкретном случае, а вообще), так это ослабить могущество перегрузки по умолчанию, сменив тип её формального параметра с auto&& на const auto&. Другой, вариант, как сделать умолчательную перегрузку ещё менее специальной — это добавить фейковый вариадик пак в конце: [](auto&&, auto&&...) { }

Ещё можно предпринять дополнительные меры по устранению коллизий между has_foo и has_bar, например, таким образом:

template<class T> concept has_foo = requires (T t) { t.foo(0); };
template<class T> concept has_bar = not has_foo<T> and requires (T t) { t.bar(""); };
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 07.06.2025 6:31 rg45 . Предыдущая версия . Еще …
Отредактировано 07.06.2025 6:26 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:16 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:10 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:09 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:08 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:07 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:06 rg45 . Предыдущая версия .
Отредактировано 07.06.2025 6:05 rg45 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.