使用 std::get<index> 访问 std::variant
Accessing std::variant using std::get<index>
如何使用 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 or _Ip 视情况而定)
candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
已更新以询问如何解决而不是错误消息的含义。
gcc 8.1's error output还包括说明:
<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();
代码 get<fi>(f)
只有在 f
也被声明为 constexpr
时才能工作;但这只有在变体中的所有类型都具有平凡的析构函数时才有可能,而 std::string
没有。
std::get<>
适用于请求在 编译时 .
已知的变体索引
如果您需要对其类型在 运行时 之前未知的变体值进行操作,惯用的方法是使用具有 std::visit
.[= 的访问者14=]
#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“通用 lambda”来实现
#include <iostream>
#include <variant>
#include <string>
int main()
{
std::variant<int, std::string> f( 0 );
std::visit( [](auto v){std::cout << v;} , f );
}
如何使用 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 or _Ip 视情况而定)
candidate template ignored: invalid explicitly-specified argument for template parameter '_Tp'
已更新以询问如何解决而不是错误消息的含义。
gcc 8.1's error output还包括说明:
<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();
代码 get<fi>(f)
只有在 f
也被声明为 constexpr
时才能工作;但这只有在变体中的所有类型都具有平凡的析构函数时才有可能,而 std::string
没有。
std::get<>
适用于请求在 编译时 .
如果您需要对其类型在 运行时 之前未知的变体值进行操作,惯用的方法是使用具有 std::visit
.[= 的访问者14=]
#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“通用 lambda”来实现
#include <iostream>
#include <variant>
#include <string>
int main()
{
std::variant<int, std::string> f( 0 );
std::visit( [](auto v){std::cout << v;} , f );
}