SaZ>Я тут пытаюсь раздуплиться с тем, как скрестить std::variant, std::visit и вариадики, что-то вообще нет мыслей. SaZ>Подскажите, в какую сторону копать?
Судя по комментарию // TODO: use variadic instead of hardcoded types проблема совсем не в вариадиках и не в std::visit.
А проблема в том, что нужно как-то сообщить компилятору, что если аргумент имеет тип int, то нужно создать экземпляр Int, а если имеет тип double, то нужно создать экземпляр Double, и.т.п.
Из кода, где объявлены struct Int, struct Double, информацию о такой взаимосвязи между типами получить, конечно, нельзя. Хотя бы потому, что где-нибудь можно написать struct Int2 : Base<int, Int2> {...}, и тогда будет совершенно непонятно что нужно создавать в ответ на int — экземпляр Int или Int2 ?
Поэтому это только твоя задача описать правила поведения в каждом случае. Можно кодом (как сейчас), но это неудобно. Другой вариант — использовать type traits, как, собственно, для кучи всего в с++ и сделано уже:
// общее правило отображение типа Src в Dst template <class Src>
struct TypeMap;
// конкретные специализацииtemplate <>
struct TypeMap<int> {
using Dst = Int;
};
template <>
struct TypeMap<double> {
using Dst = Double;
};
Ну а визитор без условий на основе этого уже тривиально делается:
p = std::make_shared<typename TypeMap<TKey>::Dst>();
Здравствуйте, SaZ, Вы писали:
SaZ>Всем доброго времени суток,
SaZ>Я тут пытаюсь раздуплиться с тем, как скрестить std::variant, std::visit и вариадики, что-то вообще нет мыслей. SaZ>Код есть тут: https://wandbox.org/permlink/WGQdh4FV7a1k8zGi
SaZ>Подскажите, в какую сторону копать?
Я правильно понял, что аргументы в вызове factoty<...> это типы, которые должны быть ассоциированы с соответствующими (по порядку следования) типами в аргументах std::variant (Var) ?
Или это просто список, а типы которым они должны соответствовать, берем из описания Base?
Тогда выделите визиотр-фабрику в отделительный класс, специализируемый для каждого финального класса:
Здравствуйте, watchmaker, Вы писали:
W>Здравствуйте, SaZ, Вы писали:
SaZ>>Я тут пытаюсь раздуплиться с тем, как скрестить std::variant, std::visit и вариадики, что-то вообще нет мыслей. SaZ>>Подскажите, в какую сторону копать?
W>Судя по комментарию // TODO: use variadic instead of hardcoded types проблема совсем не в вариадиках и не в std::visit. W>А проблема в том, что нужно как-то сообщить компилятору, что если аргумент имеет тип int, то нужно создать экземпляр Int, а если имеет тип double, то нужно создать экземпляр Double, и.т.п. W>Из кода, где объявлены struct Int, struct Double, информацию о такой взаимосвязи между типами получить, конечно, нельзя. Хотя бы потому, что где-нибудь можно написать struct Int2 : Base<int, Int2> {...}, и тогда будет совершенно непонятно что нужно создавать в ответ на int — экземпляр Int или Int2 ?
W>Поэтому это только твоя задача описать правила поведения в каждом случае. Можно кодом (как сейчас), но это неудобно. Другой вариант — использовать type traits, как, собственно, для кучи всего в с++ и сделано уже:
W>// общее правило отображение типа Src в Dst
W>template <class Src>
W>struct TypeMap;
W>// конкретные специализации
W>template <>
W>struct TypeMap<int> {
W> using Dst = Int;
W>};
W>template <>
W>struct TypeMap<double> {
W> using Dst = Double;
W>};
W>
W>Ну а визитор без условий на основе этого уже тривиально делается: W>
Здравствуйте, Chorkov, Вы писали:
C>...
C>Если визиторы невозможно написать без связывания локальных переменных, предется использовать мене читаемое решение:
C>
Благодарю. Такое же решение мне предложили на stackoverflow. Осталось адаптировать его для своей задачи, что тоже несколько нетривиально.
Мне просто достаточно редко доходилось реализовывать на практике вариадики, я пока ещё в них плаваю.
P.S. пытаюсь поставить оценку за сообщение, но почему-то она исчезает после обновления страницы.
std::visit просто не умеет принимать на вход массив лямбд, вот они и заворачивается в функтор с перегруженными скобочками, который уже понятен для std::visit.
J>Хм, кто сможет объяснить как это компилируется? В частности волнуют записи overloaded(Ts...) и overloaded{
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
Мы объявили шаблонный overloaded класс, унаследованный от всех аргументов шаблона. using Ts::operator()... мы вынесли определения операторов () из базовых классов.
Теперь все этим операторы равнозначны.
У класса есть конструктор по умолчанию, который можно было бы использовать так:
Однако такое использование, в случае лямбд, неудобно — мы не можем явно указать их типы.
Ранее эта проблема решалась написанием специальной функции make***, которая на основе типов своих аргументов
выводила бы тип результата. Примерно так:
Однако, в С++17 появился вывод параметров шаблона на основании типов аргументов конструктора (Class Template Argument Deduction).
Эта возможность призвана избавить нас от всяческих make_tuple, make_unique и т.д.
В частности, строчка
говорит, что если вызван конструктор переменной (в т.ч. временной), для шаблона overloaded, без указания параметров шаблона, то надо вызвать конструктор для класса параметризованного для типами, из аргументов конструктора.