I want to get the active value in a std::variant without knowing which one is active. I thought i could write a template visitor and use std::visit but it doesn't work.
#include <variant>
#include <string>
#include <iostream>
struct Visit_configuration {
template<typename Data_type>
Data_type operator()(Data_type& t) const
{
return t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::cout << std::visit(Visit_configuration(), v); // expect "hello"
std::cin.get();
}
MSVC doesn't compile and throws:
error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4741 23.7.7 [variant.visit]/2).
note: see reference to function template instantiation 'int std::visit&,0>(_Callable &&,std::variant &)' being compiled
So how to fix this?
edit: I want to use the obtained value maybe also for other so putting cout in the template isn't what im looking for.
Ask yourself the question:
What is the return type of std::visit
if you don't know what part of the variant
is active?
That is the question that the compiler must answer. And the answer can't be "it depends" - you (as in, the compiler) must decide on exactly one type at compile-time. The visit
call cannot possibly return different types at runtime.
If you want to work with different types "at runtime", you must be in a function templated on the type you want to work with. In other words, there must be different functions (or function template instantiations) to handle the "write an int to cout
" and "write a string to cout
" cases. You cannot do this in the same (non-templated) function.
The straightforward solution here is thus to put the std::cout <<
into your templated visitor function - that's the point of visiting: Specifying what is supposed to happen in each case.
If you want to "use the obtained value maybe also for [some] other [purpose]", then that "other purpose" should also be part of the/a visitor. Only then can you have that "other purpose" handle the different cases at once (e.g. in a templated function). Otherwise you must decide at compile-time already which type shall be used - the compiler is not going to leave that choice open for later (run time).
Return type of visitor function should be identical.
Create printer visitor instead:
struct PrinterVisitor {
template<typename T>
void operator()(const T& t) const
{
std::cout << t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit(PrinterVisitor{}, v); // expect "hello"
}
And in your case, you can even have lambda:
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit([](const auto& t){std::cout << t;}, v); // expect "hello"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With