How can I access members of variant using v.index()
then std::get<index>(v)
?
Useful when the variant has multiple entries of the same type.
The following does not work. This code doesn't compile on either GCC or clang
#include <iostream>
#include <variant>
#include <string>
#include <sstream>
typedef std::variant<int, int, std::string> foo;
std::string bar(const foo f) {
const std::size_t fi = f.index();
auto ff = std::get<fi>(f);
std::ostringstream ss;
ss << "Index:" << fi << " Value: " << ff;
return ss.str();
}
int main()
{
foo f( 0 );
std::cout << bar(f);
}
There are many versions of std::get of course, so the error messages are lengthy.
gcc complains (for every version of get<>)
prog.cc:10:29: error: the value of 'fi' is not usable in a constant expression
auto ff = std::get<fi>(f);
^
prog.cc:9:23: note: 'fi' was not initialized with a constant expression
const std::size_t fi = f.index();
^~
prog.cc:10:29: note: in template argument for type 'long unsigned int'
auto ff = std::get<fi>(f);
Clang complains (for every version of get<>) (re _Tp or _Ip as the case may be)
candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
UPDATED to ask how to solve rather than what does the error message mean.
std::get<>
is applicable when requesting a variant index that is known at compile time.
If you need to act on a variant value whose type isn't known until runtime, the idiomatic approach is to use a visitor with std::visit
.
#include <iostream>
#include <variant>
#include <string>
struct output_visitor
{
template< typename T >
void operator() ( const T& value ) const
{
std::cout << value;
}
};
int main()
{
std::variant<int, std::string> f( 0 );
std::visit( output_visitor{}, f );
}
This can often be implemented with C++14 "generic lambdas"
#include <iostream>
#include <variant>
#include <string>
int main()
{
std::variant<int, std::string> f( 0 );
std::visit( [](auto v){std::cout << v;} , f );
}