У меня есть код ниже и почему 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
У меня есть код ниже, и почему 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
,Вызов некорректен, если приведенный выше вызов не является допустимым выражением одного типа и категории значения для всех комбинаций альтернативных типов всех вариантов..
Язык может существовать со многими функциями 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*
использует относительно нелепое количество метапрограммирования, чтобы
Названные операторы, чтобы вызвать посещение,
Слияние возвращаемых значений посещений в варианте.
но ни один здравомыслящий человек не напишет этот код.
Ты можешь сделать
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);
}