Re[5]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 23.10.25 07:29
Оценка: +5
Здравствуйте, Marty, Вы писали:

S>>Может вы просто не умеете его готовить?


M>Возможно. Научи, как правильно


Может вы покажите как у вас получается через жопу и с большим количеством писанины, чтобы читатели форума могли подсказать как улучшить ситуацию? Или признать вашу правоту.

А то без кода обсуждать можно разве что ваши дурные привычки к функциям на много сотен строк.
Re[7]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 19:55
Оценка: +3
Здравствуйте, Marty, Вы писали:


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


Так это только благодаря тебе она начинается, потому что ты if-ы используешь. А так-то вообще такие штуки на перегрузках делаются. И перегрузки можно делать по-разному. Можно, лямбды использовать, можно собственные функционалы. Можно через композицию, можно через монолиты. И здесь очень востребованы оказываются концепцы и констрейнты. И код реально выглядит красиво и профессионально, не что что твои if-ы, с энумами.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.10.2025 20:00 rg45 . Предыдущая версия . Еще …
Отредактировано 23.10.2025 19:59 rg45 . Предыдущая версия .
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: 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: std::get(std::variant)
От: landerhigh Пират  
Дата: 22.10.25 21:02
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Здравствуйте!


M>Я тут начал довольно активно пользоваться std::variant, и часто возникает задача — узнать, что там во варианте лежит. Также возникает задача получить лежащее там значение.


std::visit решает все озвученные вопросы без необходимости изобретать велосипеды, которые я поскипал.

M>ЗЗЗЫ А как variant может стать value less? И как это можно продетектить? Это из-за исключений может получиться, или есть другие способы?


Ну вроде да.
Re: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 23.10.25 04:00
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Мне не нравится то, что std::get принимает std::size_t индекс


Вы точно в этом уверены?
https://en.cppreference.com/w/cpp/utility/variant/get.html:

2) Type-based value accessor: If v holds the alternative T, returns a reference to the value stored in v. Otherwise, throws std::bad_variant_access. The call is ill-formed if T is not a unique element of Types....


M>Я каждый раз для каждого variant делаю перечисление enum class, если мой variant — MyVariant, то перечисление — MyVariantKind. Имена альтернатив там в одном порядке. Пишу функцию GetKind и вроде норм. Пока было нужно всего несколько раз, и руками было достаточно просто. Но вообще идея мне понравилась, и я подумал, как бы это дело сделать совместимым с std.


Даже я, будучи паталогическим велосипедостроителем в терминальной стадии, немного в шоке от вашей идеи. Да не, даже много в шоке.
Re[3]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 23.10.25 04:00
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>>>Я тут начал довольно активно пользоваться std::variant, и часто возникает задача — узнать, что там во варианте лежит. Также возникает задача получить лежащее там значение.


L>>std::visit решает все озвученные вопросы без необходимости изобретать велосипеды, которые я поскипал.


M>Через жопу и с кучей писанины, да


Может вы просто не умеете его готовить?
Re: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 19:20
Оценка: +1
Здравствуйте, Marty, Вы писали:

M>Захотелось:

M>1) поиметь функцию типа std::index (которой на самом деле вроде нет), которая для variant'а вызывает его index() и кастит к моему enum — что тут лучше придумать? Или есть что-то такое, просто я не в курсе?
M>2) аналог std::get. Кстати, я что-то всегда вызываю std::get, но, по идее, тут должен работать просто get через ADL, и я могу написать свою пачку перегрузок get в том же NS, где и variant, и всё будет работать просто через вызов get, так?
M>3) holds_alternative, которая принимает variantKind и variant, и возвращает bool — тут по идее, так же как с get
M>4) get_if — ну это уже на базе остального делается, вроде

По-моему, во всех этих вариантах писанины будет существенно больше, чем при использовании std::visit. Для каждого типа варианта нужно написать энум, потом скастить к этому энуму индекс, потом этот энум запихнуть в какой-то switch и в конечном итоге, скорее всего, вызвать для каждого случая какую-то функцию. Ты же не будешь писать пласты кода прямо внутри switch-а.

А через std::get твоя задача (УЗНАТЬ, что лежит в вариарианте) вообще не решается. Рассчитано на то, что ты сам знаешь, что лежит в варианте и вызываешь std::get с правильным индексом или типом, в противном случае получишь исключение.

Третий и четвёртый варианты — это проверить, а не узнать.

В общем, осваивай std::variant, и твоя жизнь сразу упростится.
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 19:52
Оценка: +1
Здравствуйте, Marty, Вы писали:

R>>А как бы ты хотел чтоб это выглядело? Можешь примерчик набросать?


M>Как-то так:

M>
M>int func(MyVariant v)
M>{
M>    auto kind = getKind(v);
M>    if (kind==Kind::A)
M>    {
M>        doSomething(get<Kind::A>(v));
M>        // doSomething(get(kind, v)); // или даже так
M>    }
M>    else if (kind==Kind::B || kind==Kind::C)
M>    {
M>        log << "Error: " << enum_serialize(kind) << " not allowed here\n";
M>        return -1; // error - B or C not allowed here
M>    }
M>    else
M>    {
M>        return 0; // OK
M>    }
M>}
M>


M>Просто и понятно.


Ну и чем это проще и понятнее, чем:

https://coliru.stacked-crooked.com/a/83124dc3a3facc5d

int func(MyVariant v)
{
    return std::visit([]<typename T>(const T& t) {
        if constexpr (std::same_as<T, A>)
        {
            doSomething(t);
        }
        else if constexpr (std::same_as<T, B> or std::same_as<T, C>)
        {
            std::cout << "Error: B or C not allowed here\n";
            return -1;
        }
        return 0; // OK
    }, v);
}


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

И я привёл законченный работающий пример, а тебе ещё нужно наколбасить энумов к своим вариантам. В итоге нифига не проще будет, а будет реально куча.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.10.2025 19:53 rg45 . Предыдущая версия .
Re[5]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 24.10.25 07:57
Оценка: +1
Здравствуйте, Marty, Вы писали:

YV>>здесь


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


ИМХО, вот так гораздо проще: https://godbolt.org/z/YW839hjGY
Но идея та же самая.
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);
}
Перекуём баги на фичи!
std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 22.10.25 20:20
Оценка:
Здравствуйте!

Я тут начал довольно активно пользоваться std::variant, и часто возникает задача — узнать, что там во варианте лежит. Также возникает задача получить лежащее там значение.

Мне не нравится то, что std::get принимает std::size_t индекс, а std::variant::index() возвращает std::size_t, а std::holds_alternative принимает тип.

Я каждый раз для каждого variant делаю перечисление enum class, если мой variant — MyVariant, то перечисление — MyVariantKind. Имена альтернатив там в одном порядке. Пишу функцию GetKind и вроде норм. Пока было нужно всего несколько раз, и руками было достаточно просто. Но вообще идея мне понравилась, и я подумал, как бы это дело сделать совместимым с std.

Захотелось:
1) поиметь функцию типа std::index (которой на самом деле вроде нет), которая для variant'а вызывает его index() и кастит к моему enum — что тут лучше придумать? Или есть что-то такое, просто я не в курсе?
2) аналог std::get. Кстати, я что-то всегда вызываю std::get, но, по идее, тут должен работать просто get через ADL, и я могу написать свою пачку перегрузок get в том же NS, где и variant, и всё будет работать просто через вызов get, так?
3) holds_alternative, которая принимает variantKind и variant, и возвращает bool — тут по идее, так же как с get
4) get_if — ну это уже на базе остального делается, вроде

Как это всё лучше по красоте сделать?

ЗЫ Думаю запилить какой-нить генератор кода, который бы мне всю красоту генерил по простецкому описанию, и мой Variant, и VariantKind

ЗЗЫ Приглашается в тему Евгений Музыченко с примером своего compile-time скрипта на его гипотетическом диалекте C++, в котором есть МАКРОСЫ. Каким ему видится решение подобной задачи? Хочу почитать код такого решения.

ЗЗЗЫ А как variant может стать value less? И как это можно продетектить? Это из-за исключений может получиться, или есть другие способы?
Маньяк Робокряк колесит по городу
Re[2]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 22.10.25 21:22
Оценка:
Здравствуйте, landerhigh, Вы писали:

M>>Я тут начал довольно активно пользоваться std::variant, и часто возникает задача — узнать, что там во варианте лежит. Также возникает задача получить лежащее там значение.


L>std::visit решает все озвученные вопросы без необходимости изобретать велосипеды, которые я поскипал.


Через жопу и с кучей писанины, да


M>>ЗЗЗЫ А как variant может стать value less? И как это можно продетектить? Это из-за исключений может получиться, или есть другие способы?


L>Ну вроде да.


Это я видел
Маньяк Робокряк колесит по городу
Re[2]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 06:21
Оценка:
Здравствуйте, so5team, Вы писали:

M>>Мне не нравится то, что std::get принимает std::size_t индекс


S>Вы точно в этом уверены?


Точно:

1) Index-based value accessor: If v.index() == I, returns a reference to the value stored in v. Otherwise, throws std::bad_variant_access. The call is ill-formed if I is not a valid index in the variant.



M>>Я каждый раз для каждого variant делаю перечисление enum class, если мой variant — MyVariant, то перечисление — MyVariantKind. Имена альтернатив там в одном порядке. Пишу функцию GetKind и вроде норм. Пока было нужно всего несколько раз, и руками было достаточно просто. Но вообще идея мне понравилась, и я подумал, как бы это дело сделать совместимым с std.


S>Даже я, будучи паталогическим велосипедостроителем в терминальной стадии, немного в шоке от вашей идеи. Да не, даже много в шоке.


Ну, бывает.
Маньяк Робокряк колесит по городу
Re[4]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 06:22
Оценка:
Здравствуйте, so5team, Вы писали:

L>>>std::visit решает все озвученные вопросы без необходимости изобретать велосипеды, которые я поскипал.


M>>Через жопу и с кучей писанины, да


S>Может вы просто не умеете его готовить?


Возможно. Научи, как правильно
Маньяк Робокряк колесит по городу
Re[3]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 23.10.25 07:24
Оценка:
Здравствуйте, Marty, Вы писали:

M>>>Мне не нравится то, что std::get принимает std::size_t индекс


S>>Вы точно в этом уверены?


M>Точно:


Вы специально проигнорировали цитату про второй вариант std::get-а?
Re[3]: std::get(std::variant)
От: landerhigh Пират  
Дата: 23.10.25 09:32
Оценка:
Здравствуйте, Marty, Вы писали:

L>>std::visit решает все озвученные вопросы без необходимости изобретать велосипеды, которые я поскипал.

M>Через жопу и с кучей писанины, да

Можно и через жопу. И даже с кучей писанины. В плюсах вообще можно всё.
Но зачем?
Re[3]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 18:39
Оценка:
Здравствуйте, Marty, Вы писали:

L>>std::visit решает все озвученные вопросы без необходимости изобретать велосипеды, которые я поскипал.


M>Через жопу и с кучей писанины, да


Да прям уж куча:

https://coliru.stacked-crooked.com/a/3bf34d7526b1245c

    std::visit([](auto&& t) {
        std::cout << "Тут лежит " << t << std::endl;
    }, v);


А как бы ты хотел чтоб это выглядело? Можешь примерчик набросать?
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.10.2025 18:50 rg45 . Предыдущая версия . Еще …
Отредактировано 23.10.2025 18:42 rg45 . Предыдущая версия .
Отредактировано 23.10.2025 18:40 rg45 . Предыдущая версия .
Re[4]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 19:11
Оценка:
Здравствуйте, rg45, Вы писали:

R>Да прям уж куча:


Именно что куча


R>https://coliru.stacked-crooked.com/a/3bf34d7526b1245c


R>
R>    std::visit([](auto&& t) {
R>        std::cout << "Тут лежит " << t << std::endl;
R>    }, v);
R>


R>А как бы ты хотел чтоб это выглядело? Можешь примерчик набросать?


Как-то так:
int func(MyVariant v)
{
    auto kind = getKind(v);
    if (kind==Kind::A)
    {
        doSomething(get<Kind::A>(v));
        // doSomething(get(kind, v)); // или даже так
    }
    else if (kind==Kind::B || kind==Kind::C)
    {
        log << "Error: " << enum_serialize(kind) << " not allowed here\n";
        return -1; // error - B or C not allowed here
    }
    else
    {
        return 0; // OK
    }

    //...

}


Просто и понятно.

Или switch(kind) сделать, или ещё что
Маньяк Робокряк колесит по городу
Отредактировано 23.10.2025 20:00 Marty . Предыдущая версия . Еще …
Отредактировано 23.10.2025 19:18 Marty . Предыдущая версия .
Re[4]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 19:19
Оценка:
Здравствуйте, so5team, Вы писали:

S>Вы специально проигнорировали цитату про второй вариант std::get-а?


Да
Маньяк Робокряк колесит по городу
Re[5]: std::get(std::variant)
От: landerhigh Пират  
Дата: 23.10.25 19:23
Оценка:
Здравствуйте, Marty, Вы писали:

M>Как-то так:

  Скрытый текст
M>
M>int func(MyVariant v)
M>{
M>    auto kind = getKind(v);
M>    if (kind==Kind::A)
M>    {
M>        doSomething(get<Kind::A>(v));
M>        // doSomething(get(kind, v)); // или даже так
M>    }
M>    else if (kind==Kind::B || kind==Kind::C)
M>    {
M>        log << "Error: " << enum_serialize(kind) << " not allowed here\n";
M>        return -1; // error - B or C not allowed here
M>    }
M>    else
M>    {
M>        return 0; // OK
M>    }
M>}
M>


    std::visit([](auto&& t) {
        if constexpr(std::is_same_v(t, Kind::A)) 
        {
        }
        else if constexpr(std::is_same_v(t, Kind::B))
        {
        }
    }, v);




Можно еще и приукрасить, как тут написано.
Re[2]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 19:27
Оценка:
Здравствуйте, rg45, Вы писали:

R>По-моему, во всех этих вариантах писанины будет существенно больше, чем при использовании std::visit. Для каждого типа варианта нужно написать энум, потом скастить к этому энуму индекс,


Генератор кода


R>потом этот энум запихнуть в какой-то switch и в конечном итоге, скорее всего, вызвать для каждого случая какую-то функцию. Ты же не будешь писать пласты кода прямо внутри switch-а.


Или не вызвать, а выйти из текущей


R>А через std::get твоя задача (УЗНАТЬ, что лежит в вариарианте) вообще не решается. Рассчитано на то, что ты сам знаешь, что лежит в варианте и вызываешь std::get с правильным индексом или типом, в противном случае получишь исключение.


ну да, для узнать это get_if или holds_alternative


R>Третий и четвёртый варианты — это проверить, а не узнать.


R>В общем, осваивай std::variant, и твоя жизнь сразу упростится.


Я как-то осваивал std::variant, пиша (пися? писая?) тулзу с использованием LLVM. Мягко говоря, осталось впечатление, что это полный п надо бы как-то попроще всё это
Маньяк Робокряк колесит по городу
Re[6]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 19:31
Оценка:
Здравствуйте, landerhigh, Вы писали:

Вместо
if (kind==Kind::B || kind==Kind::C)
{
}


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


L>
L>    std::visit([](auto&& t) {
L>        if constexpr(std::is_same_v(t, Kind::A)) 
L>        {
L>        }
L>        else if constexpr(std::is_same_v(t, Kind::B))
L>        {
L>        }
L>    }, v);
L>


L>


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

Ещё бесит, что в visit значение варианта передаётся после обработчика. Почему нельзя было его первым аргументом? Оно за портянкой лямбды теряется совсем
Маньяк Робокряк колесит по городу
Re[2]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 19:40
Оценка:
Здравствуйте, rg45, Вы писали:

R>В общем, осваивай std::variant, и твоя жизнь сразу упростится.


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

auto kind = getKind(v);
name = getName(kind, v);


Как мне такое сделать?

Я пока портяночно написал, но вот думаю, как бы можно было бы это лучше сделать.

например:

string getNameImpl(Kind kind, Variant v, initializer_list<Kind> hasNameList)
{
    for(auto k: hasNameList)
    {
        if (k==kind)
            return visit([](auto a) { return a.name; });
    }

    return string();
}

string getName(Kind kind, Variant v)
{
    return getNameImpl(kind, x, {Kind::A, Kind::B, ...});
}


Ну или как-то так

Тут наверное без вариадик тайплиста не обойтись, но хочется как-то попроще
Маньяк Робокряк колесит по городу
Отредактировано 23.10.2025 19:52 Marty . Предыдущая версия . Еще …
Отредактировано 23.10.2025 19:49 Marty . Предыдущая версия .
Re[6]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 19:59
Оценка:
Здравствуйте, rg45, Вы писали:

M>>Просто и понятно.


R>Ну и чем это проще и понятнее, чем:


R>https://coliru.stacked-crooked.com/a/83124dc3a3facc5d


R>
R>int func(MyVariant v)
R>{
R>    return std::visit([]<typename T>(const T& t) {
R>        if constexpr (std::same_as<T, A>)
R>        {
R>            doSomething(t);
R>        }
R>        else if constexpr (std::same_as<T, B> or std::same_as<T, C>)
R>        {
R>            std::cout << "Error: B or C not allowed here\n";
R>            return -1;
R>        }
R>        return 0; // OK
R>    }, v);
R>}
R>


в ветке doSomething(t); я не хочу выходить из func. Надо было там написать после if продолжение кода — //.... Поправлю для остальных


R>И это не единственный, и не лучший, кстати, вариант использования — тут на перегрузках можно реально по красоте всё сделать.


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


Генератор

А можно в рантайме, в какой-нибудь другой подсистеме, сформировать список альтернатив, которые нужно обработать, и передать в обработчик вместе с variant'ом?
Маньяк Робокряк колесит по городу
Re[7]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:00
Оценка:
Здравствуйте, Marty, Вы писали:

M>Генератор


Ну так если генератор, тогда не понятно, зачем было эту тему создавать.
--
Справедливость выше закона. А человечность выше справедливости.
Re[8]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 20:02
Оценка:
Здравствуйте, rg45, Вы писали:

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


R>Так это только благодаря тебе она начинается, потому что ты if-ы используешь. А так-то вообще такие штуки на перегрузках делаются. И перегрузки можно делать по-разному. Можно, лямбды использовать, можно собственные функционалы. Можно через композицию, можно через монолиты. И здесь очень востребованы оказываются концепцы и констрейнты. И код реально выглядит красиво и профессионально, не что что твои if-ы, с энумами.


Нет под рукой ссылки, где можно почитать такой прекрасный код?
Маньяк Робокряк колесит по городу
Re[7]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:04
Оценка:
Здравствуйте, Marty, Вы писали:

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


M>>>Просто и понятно.


R>>Ну и чем это проще и понятнее, чем:


R>>https://coliru.stacked-crooked.com/a/83124dc3a3facc5d


R>>
R>>int func(MyVariant v)
R>>{
R>>    return std::visit([]<typename T>(const T& t) {
R>>        if constexpr (std::same_as<T, A>)
R>>        {
R>>            doSomething(t);
R>>        }
R>>        else if constexpr (std::same_as<T, B> or std::same_as<T, C>)
R>>        {
R>>            std::cout << "Error: B or C not allowed here\n";
R>>            return -1;
R>>        }
R>>        return 0; // OK
R>>    }, v);
R>>}
R>>


M>в ветке doSomething(t); я не хочу выходить из func. Надо было там написать после if продолжение кода — //.... Поправлю для остальных


Так просто убери else после if-а и пиши, что хочешь. Я же опирался на твой прототип.
--
Справедливость выше закона. А человечность выше справедливости.
Re[8]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 20:11
Оценка:
Здравствуйте, rg45, Вы писали:

R>>>
R>>>    return std::visit([]<typename T>(const T& t) {
R>>>


О, шаблонная лямбда? Не встречал такого. Через жопу писал (auto a) и затем тип выводил через declspec/decay


M>>в ветке doSomething(t); я не хочу выходить из func. Надо было там написать после if продолжение кода — //.... Поправлю для остальных


R>Так просто убери else после if-а и пиши, что хочешь. Я же опирался на твой прототип.


Ну, может ты и прав.

А где бы всё же полюбоваться на божественный код с variant'ами? Для общего развития?

И как списки альтернатив передавать между подсистемами в рантайме?
Маньяк Робокряк колесит по городу
Re[9]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:19
Оценка:
Здравствуйте, Marty, Вы писали:

M>Нет под рукой ссылки, где можно почитать такой прекрасный код?


Ну вот этот
Автор: Marty
Дата: 23.10 22:11
твой пример, без особого труда мог бы выглятеть как-то вот так:

void func(MyVariant v)
{
  return MyVisit(v,    
    [](const A& a) {
      doSomething(a);
      return 1;
    },
    [](const AnyTypeOfList<B, C> auto&) {
      log << "Error: B or C not allowed here not allowed here\n";
      return -1;
    },
    [](const auto&) {
      return 0; // OK
    }
  );
}


Прекрасно, не прекрасно, но по-любому лучше, чем твои if-ы с энумами, я считаю.
--
Справедливость выше закона. А человечность выше справедливости.
Re[9]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:21
Оценка:
Здравствуйте, Marty, Вы писали:

M>А где бы всё же полюбоваться на божественный код с variant'ами? Для общего развития?


Вот, любуйся: https://rsdn.org/forum/cpp/9009026.1
Автор: rg45
Дата: 23.10 23:19


Рабочие примеры, я уже задолбался писать, честно говоря. Но поверь, для того, чтобы добиться такого, требуется всего пол экрана вспомогательного повторно используемого кода.
--
Справедливость выше закона. А человечность выше справедливости.
Re[10]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 20:33
Оценка:
Здравствуйте, rg45, Вы писали:

R>Ну вот этот
Автор: Marty
Дата: 23.10 22:11
твой пример, без особого труда мог бы выглятеть как-то вот так:


R>
R>void func(MyVariant v)
R>{
R>  return MyVisit(v,    
R>    [](const A& a) {
R>      doSomething(a);
R>      return 1;
R>    },
R>    [](const AnyTypeOfList<B, C> auto&) {
R>      log << "Error: B or C not allowed here not allowed here\n";
R>      return -1;
R>    },
R>    [](const auto&) {
R>      return 0; // OK
R>    }
R>  );
R>}
R>


А как выглядит MyVisit?


R>Прекрасно, не прекрасно, но по-любому лучше, чем твои if-ы с энумами, я считаю.


Ну, может и лучше.

Но я сейчас в жоском эмбеде, проект на чистой сишечке.
Я пилю вспомогательную тулзу
Автор: Marty
Дата: 13.09 17:25
на плюсах, разбираю сишечную метадату через CastXML. В принципе, уже сделал на говне, решил разобраться, как можно было бы сделать лучше. И да, мои if/else/switch для поддержки были бы гораздо проще кому-то из команды кроме меня.

ЗЫ А в частном порядке нельзя с тобой связаться, если ты не против? А то код проекта не могу показывать на публику, но в частном порядке думаю можно. А ты бы мог без труда найти дерьмовые решения, и показать на форуме только их, чтобы всем было полезно.
Наверное, нахрен тебе не надо
Маньяк Робокряк колесит по городу
Отредактировано 23.10.2025 20:34 Marty . Предыдущая версия .
Re[10]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 20:34
Оценка:
Здравствуйте, rg45, Вы писали:

R>я уже задолбался писать


Ну извини
Маньяк Робокряк колесит по городу
Re[11]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:36
Оценка:
Здравствуйте, Marty, Вы писали:

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


R>>Ну вот этот
Автор: Marty
Дата: 23.10 22:11
твой пример, без особого труда мог бы выглятеть как-то вот так:


R>>
R>>void func(MyVariant v)
R>>{
R>>  return MyVisit(v,    
R>>    [](const A& a) {
R>>      doSomething(a);
R>>      return 1;
R>>    },
R>>    [](const AnyTypeOfList<B, C> auto&) {
R>>      log << "Error: B or C not allowed here not allowed here\n";
R>>      return -1;
R>>    },
R>>    [](const auto&) {
R>>      return 0; // OK
R>>    }
R>>  );
R>>}
R>>


M>А как выглядит MyVisit?


Эскизно примерно вот так:

decltype(auto) MyVisit(auto&& t, Callable auto&&...f)
{
   return std::visit(Overloaded(f...), v);
}
--
Справедливость выше закона. А человечность выше справедливости.
Re[11]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:40
Оценка:
Здравствуйте, Marty, Вы писали:

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

M>Наверное, нахрен тебе не надо

Можно. Только не сегодня, ладно?

Я сделаю все необходимые вспомогательные утилиты (благо их не так уж много), а ты придумай какой-нибудь синтетический, не очень сложный, но более-менее осмысленный пример, на котором можно будет обкатать. И выкладывай пример прямо сюда. Я на днях по свободке запилю.
--
Справедливость выше закона. А человечность выше справедливости.
Отредактировано 23.10.2025 20:45 rg45 . Предыдущая версия . Еще …
Отредактировано 23.10.2025 20:41 rg45 . Предыдущая версия .
Re[3]: std::get(std::variant)
От: rg45 СССР  
Дата: 23.10.25 20:44
Оценка:
Здравствуйте, Marty, Вы писали:

M>
M>auto kind = getKind(v);
M>name = getName(kind, v);
M>


M>Как мне такое сделать?


Да выброси ты свои kind-ы, это вчерашний день. Ты ж пойми, эти кайнды тебе нужны только для того, чтобы сделать диспетченизацию и полиморфизм. Больше ни зачем.
--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 23.10.25 20:49
Оценка:
Здравствуйте, rg45, Вы писали:

M>>Как мне такое сделать?


R>Да выброси ты свои kind-ы, это вчерашний день. Ты ж пойми, эти кайнды тебе нужны только для того, чтобы сделать диспетченизацию и полиморфизм. Больше ни зачем.


В целом, я понимаю, но современный сипипи много шума даёт, пытаюсь найти вариант, который бы использовал современный язык, но был бы прост для поддержки
Маньяк Робокряк колесит по городу
Re[3]: std::get(std::variant)
От: YuriV  
Дата: 23.10.25 21:37
Оценка:
Здравствуйте, Marty, Вы писали:

Можно так:

template<typename ... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<typename ... Ts> overloaded(Ts...) -> overloaded<Ts...>;

// use concept if liked
template <typename T> concept has_name = 
    requires(T a) {{a.name}->std::convertible_to<std::string>;};

// ...
if(k==kind)
  return std::visit(overloaded{
      [](auto && t) -> std::string requires requires {{t.name} -> std::convertible_to<std::string>;}  { return t.name; }
      , [](auto && t) -> std::string requires (not requires {{t.name} -> std::convertible_to<std::string>;}) { return {}; }
  }, v);


здесь
Re[5]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 24.10.25 05:04
Оценка:
Здравствуйте, Marty, Вы писали:

S>>Вы специально проигнорировали цитату про второй вариант std::get-а?


M>Да


Да уж. "Если факты не согласуются с нашей точкой зрения, то тем хуже для фактов".
Re[3]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 24.10.25 05:07
Оценка:
Здравствуйте, Marty, Вы писали:

M>
M>    return getNameImpl(kind, x, {Kind::A, Kind::B, ...});
M>


M>Ну или как-то так


Простите, а вот этот вот список {Kind::A, Kind::B, ...} -- он откуда возьмется?
Его программист должен ручками написать? Типа "я помню, что в структуре A есть атрибут name, поэтому Kind::A нужно включить в этот список". Правильно?
Re[4]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 24.10.25 06:50
Оценка:
Здравствуйте, so5team, Вы писали:

M>>
M>>    return getNameImpl(kind, x, {Kind::A, Kind::B, ...});
M>>


M>>Ну или как-то так


S>Простите, а вот этот вот список {Kind::A, Kind::B, ...} -- он откуда возьмется?

S>Его программист должен ручками написать? Типа "я помню, что в структуре A есть атрибут name, поэтому Kind::A нужно включить в этот список". Правильно?

Типа того. Но в моей задаче я разбирал XML, можно было оттуда выцепить и сгенерить код
Маньяк Робокряк колесит по городу
Re[5]: std::get(std::variant)
От: so5team https://stiffstream.com
Дата: 24.10.25 07:03
Оценка:
Здравствуйте, Marty, Вы писали:

S>>Простите, а вот этот вот список {Kind::A, Kind::B, ...} -- он откуда возьмется?

S>>Его программист должен ручками написать? Типа "я помню, что в структуре A есть атрибут name, поэтому Kind::A нужно включить в этот список". Правильно?

M>Типа того. Но в моей задаче я разбирал XML, можно было оттуда выцепить и сгенерить код


Ну так говно же.

Современный C++ позволяет сделать это проще. Выше тов.YuriV уже показал набросок.
Re[4]: std::get(std::variant)
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 24.10.25 07:39
Оценка:
Здравствуйте, YuriV, Вы писали:

YV>Можно так:


YV>
YV>template<typename ... Ts> struct overloaded : Ts... { using Ts::operator()...; };
YV>template<typename ... Ts> overloaded(Ts...) -> overloaded<Ts...>;

YV>// use concept if liked
YV>template <typename T> concept has_name = 
YV>    requires(T a) {{a.name}->std::convertible_to<std::string>;};

YV>// ...
YV>if(k==kind)
YV>  return std::visit(overloaded{
YV>      [](auto && t) -> std::string requires requires {{t.name} -> std::convertible_to<std::string>;}  { return t.name; }
YV>      , [](auto && t) -> std::string requires (not requires {{t.name} -> std::convertible_to<std::string>;}) { return {}; }
YV>  }, v);
YV>


YV>здесь


Спасибо, поизучаю. Но я бы не сказал, что это всё очень просто
Маньяк Робокряк колесит по городу
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[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 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.