使用 std::get 访问 std::variant<index>

Accessing std::variant using std::get<index>

本文关键字:std gt lt index variant get 访问 使用      更新时间:2023-10-16

如何使用v.index()然后使用std::get<index>(v)访问变体的成员?

当变体具有多个相同类型的条目时非常有用。

以下内容不起作用。此代码既不能在GCC上编译,也不能在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);
}

std::get当然有很多版本,所以错误消息很长。

gcc抱怨(对于每个版本的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抱怨(对于每个版本的get<>((re_Tp或_Ip,视情况而定(

candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp' 

Wandbox

更新后询问如何解决,而不是错误消息的含义。

std::get<>适用于请求在编译时已知的变量索引。

如果您需要对一个直到运行时才知道其类型的变量值执行操作,惯用方法是使用具有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 );
}

这通常可以用C++14"来实现;通用lambdas";

#include <iostream>
#include <variant>
#include <string>
int main()
{
std::variant<int, std::string> f( 0 );
std::visit( [](auto v){std::cout << v;} , f );
}

gcc 8.1的错误输出还包括解释:

<source>:10:29: error: the value of 'fi' is not usable in a constant expression
auto ff = std::get<fi>(f);
^
<source>:9:23: note: 'fi' was not initialized with a constant expression
const std::size_t fi = f.index();

整数模板参数必须是常量表达式。f不是一个常量表达式,因此对其非静态成员函数的调用不是一个常数表达式,因此fi不是。

您可以使用获得更好的错误消息

constexpr std::size_t fi = f.index();

只有当f也被声明为constexpr时,代码get<fi>(f)才能工作;但只有当变体中的所有类型都有平凡的析构函数时,这才有可能,而std::string没有。