Re[7]: std::get(std::variant)
От: landerhigh Пират  
Дата: 24.10.25 09:04
Оценка:
Здравствуйте, Marty, Вы писали:

M>у нас намечается простыня


Это у вас намечается

if constexpr(std::is_same_v(t, typeA) || std::is_same_v(t, typeB))
{
}


M>А как мне выйти из функции, которая вызывает std::visit, по какой-нибудь альтернативе?


Не распарсил.

M>Ещё бесит, что в visit значение варианта передаётся после обработчика. Почему нельзя было его первым аргументом? Оно за портянкой лямбды теряется совсем


Ну, у меня это единственная претензия к std::visit.
Re[8]: std::get(std::variant)
От: rg45 СССР  
Дата: 24.10.25 10:35
Оценка:
Здравствуйте, landerhigh, Вы писали:

M>>Ещё бесит, что в visit значение варианта передаётся после обработчика. Почему нельзя было его первым аргументом? Оно за портянкой лямбды теряется совсем


L>Ну, у меня это единственная претензия к std::visit.


Ну, почему в std::visit так сделано, понятно — потому что там это не единичное значение, а вариадик. А для одного значения действительно удобнее, когда сначала идет вариант, а за ним обработчики. Вот поэтому я и делаю обычно несложную обертку вокруг std::visit, типа как показано здесь
Автор: rg45
Дата: 23.10 23:36
. А заодно это обертка включает в себя и overloaded, и использующий код получается аккуратным и очищенным от лишних технических подробностей, типа как здесь
Автор: rg45
Дата: 23.10 23:19
. Но это всё косметика, по большому счёту.
--
Справедливость выше закона. А человечность выше справедливости.
Re[11]: std::get(std::variant)
От: rg45 СССР  
Дата: 24.10.25 10:38
Оценка:
Здравствуйте, Marty, Вы писали:

M>ЗЫ А в частном порядке нельзя с тобой связаться, если ты не против? А то код проекта не могу показывать на публику, но в частном порядке думаю можно. А ты бы мог без труда найти дерьмовые решения, и показать на форуме только их, чтобы всем было полезно.


Я смотрю, здесь уже накидали рабочих примеров, так что мне и добавить особо нечего. Дальше уже эту идею можно развивать в прикладной области с использованием концептов/констрейнтов и с добавлением синтаксического сахара
Автор: rg45
Дата: 23.10 23:36
по вкусу.
--
Справедливость выше закона. А человечность выше справедливости.
Re[6]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 24.10.25 20:53
Оценка:
Здравствуйте, so5team, Вы писали:

YV>>>здесь


M>>Спасибо, поизучаю. Но я бы не сказал, что это всё очень просто


S>ИМХО, вот так гораздо проще: https://godbolt.org/z/YW839hjGY

S>Но идея та же самая.

Спс.

Правда, я пока на 17ом стандарте, и ещё вопрос, насколько это смогут поддерживать сишники
Маньяк Робокряк колесит по городу
Re[7]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 25.10.25 06:07
Оценка: +1 :))
Здравствуйте, Marty, Вы писали:

M>Здравствуйте, so5team, Вы писали:


YV>>>>здесь


M>>>Спасибо, поизучаю. Но я бы не сказал, что это всё очень просто


S>>ИМХО, вот так гораздо проще: https://godbolt.org/z/YW839hjGY

S>>Но идея та же самая.

M>Спс.


M>Правда, я пока на 17ом стандарте


Для C++17 у меня получилось что-то вроде: https://godbolt.org/z/YnehMhsT9
Но не покидает ощущение, что более продвинутые в современном C++ товарищи смогут сделать проще и компактнее.

M>и ещё вопрос, насколько это смогут поддерживать сишники


Си-шники должны страдать. По определению.
Re[8]: std::get(std::variant)
От: rg45 СССР  
Дата: 25.10.25 07:49
Оценка:
Здравствуйте, so5team, Вы писали:

S>Для C++17 у меня получилось что-то вроде: https://godbolt.org/z/YnehMhsT9

S>Но не покидает ощущение, что более продвинутые в современном C++ товарищи смогут сделать проще и компактнее.

Не претендую на звание более продвинутого, но свой вариант предложу, всё-таки:

https://godbolt.org/z/e135r78jY

#include <string>
#include <variant>
#include <iostream>
#include <type_traits>

void has_name_aux(...);
template<typename T> auto has_name_aux(const T& t) -> decltype(t.name);
template<typename T> constexpr bool has_name_v =
    std::is_same_v<std::string, decltype(has_name_aux(std::declval<T>()))>;

template <typename...T>
std::string getName(const std::variant<T...>& v)
{
    return std::visit(
        []<typename X>(X&& x) -> std::string {
            if constexpr(has_name_v<X>)
                return x.name;
            else
                return {};
        }
        , v);
}

int main()
{
    struct a { std::string name{"a"};};
    struct b { };
    struct c { std::string name{"c"};};

    using Variant = std::variant<a, b, c, double>;

    auto test = [](const Variant& v) {
        auto const & name = getName(v);
        std::cout << (name.empty() ? "<<unnamed>>" : name) << '\n';
    };
    test(a{});
    test(b{});
    test(c{});
    test(3.14);
}

a
<<unnamed>>
c
<<unnamed>>
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 25.10.2025 8:13 rg45 . Предыдущая версия . Еще …
Отредактировано 25.10.2025 8:07 rg45 . Предыдущая версия .
Отредактировано 25.10.2025 8:06 rg45 . Предыдущая версия .
Отредактировано 25.10.2025 8:06 rg45 . Предыдущая версия .
Отредактировано 25.10.2025 7:55 rg45 . Предыдущая версия .
Re: std::get(std::variant)
От: Chorkov Россия  
Дата: 27.10.25 07:53
Оценка: 8 (1) +1
Здравствуйте, Marty, Вы писали:

Еще один вариант: перенос специализации c операторов () визитора, на специализацию свободных функций:

struct a { std::string name{"a"};};
struct b { };
struct c { std::string name{"c"};};
struct d { };
using Variant = std::variant<a, b, c, d>;


template<typename T>
auto getName(const T& v) -> decltype(v.name) { return v.name; }  // можнос специализировать типы по наличию поля

inline std::string getName(const d& v) { return "type d"; }  // можнос специализировать конкретные типы

// Все варианты типов, что не подошли под спефиализации. Наименее приоритетный вариант.
inline std::string getName(...) { return ""; }

template<typename ...T>
std::string getName(const std::variant<T...>& v) // Работа с variant обязательно шаблонная. Иначе можно попасть в рекурсивный вызов для не специализированного класса.
{ 
    return std::visit( [](const auto& vi)->std::string { return getName(vi); }, v ); 
}


Плюсы:
В случае, когда конкретный тип заранее известен, будет сразу вызваны функции для конкретных типов, избегая диспетчеризации в visit.
Можно писать код в "распределенном" режиме, определяя getName для новых классов рядом с классом.
с++17 — достаточно. Можно и на c++11, но специализация по признаку наличия поля — сильно многословнее.
Отредактировано 27.10.2025 8:32 Chorkov . Предыдущая версия . Еще …
Отредактировано 27.10.2025 8:01 Chorkov . Предыдущая версия .
Re[2]: std::get(std::variant)
От: rg45 СССР  
Дата: 27.10.25 08:26
Оценка: +1
Здравствуйте, Chorkov, Вы писали:

C>Плюсы:

C>В случае, когда конкретный тип заренее известве, буджут сразу вызваны функции для конкретных типов, избегая диспетчеризации в visit.

Ещё один плюс — подключается ADL. Это значит, что getName становится тем, что в стандартной библиотеке обозначается как customization point.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 27.10.2025 15:10 rg45 . Предыдущая версия .
Re[3]: std::get(std::variant)
От: Кодт Россия  
Дата: 01.11.25 02:17
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Или вот вот такой пример. Есть variant с парой десятков альтернатив. У половины альтернатив есть атрибут name, у других нет. Я хочу функцию, которая возвращает name, если он есть, или пустую строку, если его нет. Чтобы выше не парится, выписывая везде std::visit для получения этого атрибута.


auto try_get_name(const auto& variant) {
  return std::visit(
    [](const auto& value) {
      if constexpr(requires{value.name}) {
        return value.name;
      } else {
        return std::string{};
      }
    },
    variant);
}
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.