как вернуть определенный тип из варианта с помощью посетителя?

У меня есть код ниже и почему visitor1 а также visitor2 дает ошибки?
Означает ли это, что посетитель не может вернуть один тип в варианте?

#include <iostream>
#include <variant>struct Visitor1
{
template <class T>
T operator()(const T & t) const
{
return (t);
}
};

struct Visitor2
{
int operator()(const int  & t) const
{
return std::get<int>(t);
}

char operator()(const char & t) const
{
return std::get<char>(t);
}
};

struct Visitor3
{
void operator()(const int & t) const
{
std::cout<<t;
}
void operator()(const char & t) const
{
std::cout<<t;
}
};

int main()
{
std::variant<int, char> v{char(100)};

std::visit(Visitor3{}, v);

auto t = std::visit(Visitor2{}, v);  //fails
//auto t = std::visit(Visitor1{}, v); //fails
std::cout << t;
}

Я знаю, что могу использовать std::get(), но проблема в том, что я могу использовать только auto с std::get(), если я сделаю что-то вроде ниже, x недоступен за пределами области if / else:

bool b;
Variant v;
if (b)
{
auto x = std::get<int>(v);
}
else
{
auto x = std::get<char>(v);
}
// I want to do something with x here out of if/else

2

Решение

У меня есть код ниже, и почему visitor1 и visitor2 выдают ошибки?

Потому что C ++ — строго типизированный язык.

Когда ты пишешь

auto t = std::visit(Visitor2{}, v);  //fails

компилятор должен решить время компиляции, какой тип t, так должен решить, какой тип возврата std::visit(Visitor2{}, v),

Если Visitor2 вернуть char, когда v содержит charили int, когда v содержать int, компилятор не может выбрать (время компиляции!) тип, возвращаемый из std::visit() [есть также проблема (Visitor2 только это tвнутри operator()х, это int или char, так что вы не можете подать заявку std::get() к этому].

Та же проблема с Visitor1: шаблон operator() вернуть тип шаблона так int или же char для std::variant<int, char>,

Visitor3 работает потому что оба operator() вернуть voidТаким образом, компилятор может решить (время компиляции), что std::visit(Visitor3{}, v) возврат (в некотором смысле) void,

Может быть, лучше объяснить в эта страница:

[std::visit()] Эффективно возвращается

std::invoke(std::forward<Visitor>(vis), std::get<is>(std::forward<Variants>(vars))...)

, где is... является vars.index()..., Тип возвращаемого значения выводится из возвращаемого выражения, как если бы decltype,

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

2

Другие решения

Язык может существовать со многими функциями C ++, который делает то, что вы хотите.

Для того, чтобы делать то, что вы хотите, когда вы звоните std::visitНеобходимо написать N различных реализаций остальной функции.

В каждой из этих N различных реализаций (в вашем случае 2) тип переменной будет разным.

C ++ не работает таким образом.

Единственная часть кода, которая «умножается» на вызов, — это посетитель.

int main()
{
std::variant<int, char> v{char(100)};

std::visit([&](auto && t){
std::cout << t;
}, v);
}

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

Все, что возвращается от посещения возвращается к «единственному экземпляру» тела вызывающей области.

В принципе, [&](auto&& t) лямбды делают то, что ты хочешь.


Теперь мы можем сделать несколько трюков, чтобы немного изменить синтаксис.

Мой любимый:

v->*visit*[&](auto&& val) {
std::cout << val;
return [val](auto&& x) { x << val; };
}->*visit*[&](auto&& outputter) {
outputer(std::cout);
};

где ->*visit* использует относительно нелепое количество метапрограммирования, чтобы

  1. Названные операторы, чтобы вызвать посещение,

  2. Слияние возвращаемых значений посещений в варианте.

но ни один здравомыслящий человек не напишет этот код.

2

Ты можешь сделать

bool b;
Variant v;
std_optional<char> x_char;
std_optional<int> x_int;
if (b)
{
x_int = std::get<int>(v);
}
else
{
x_char = std::get<char>(v);
}
1
По вопросам рекламы [email protected]