c++ : std::visit 在 gcc 下不可编译
c++ : std::visit not compilable under gcc
这是我的代码,可以很好地编译 clang,但在 gcc 中编译失败
#include <iostream>
#include <string>
#include <regex>
#include <variant>
struct Id {
void SetValue(const std::string& item)
{
value = item;
}
std::string value;
};
struct Number {
void SetValue(const std::string& item)
{
value = std::stoi(item);
}
int value;
};
using TokenBase
= std::variant<Number, Id>;
struct Token : TokenBase {
using TokenBase::TokenBase;
template <typename T>
[[nodiscard]] bool Is() const {
return std::holds_alternative<T>(*this);
}
template <typename T>
[[nodiscard]] const T& As() const {
return std::get<T>(*this);
}
template <typename T>
[[nodiscard]] const T* TryAs() const {
return std::get_if<T>(this);
}
};
struct LexerTokenExtractor {
const std::string& item_;
void operator()(Number& item) const {
item.SetValue(item_);
}
void operator()(Id& item) const {
item.SetValue(item_);
}
};
int main()
{
const std::string string_token("x");
Token id_token = Id();
std::visit(LexerTokenExtractor{string_token}, id_token);
std::cout << "ok" << std::endl;
}
这是日志:
required from here
/usr/include/c++/7/variant:97:29: error: incomplete type ‘std::variant_size<Token>’ used in nested name specifier
inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
/usr/include/c++/7/variant: In instantiation of ‘constexpr const auto std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>::_S_vtable’:
/usr/include/c++/7/variant:711:29: required from ‘struct std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>’
/usr/include/c++/7/variant:1255:23: required from ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = LexerTokenExtractor; _Variants = {Token&}]’
1673947047/source.cpp:65:57: required from here
/usr/include/c++/7/variant:711:49: error: ‘_S_apply’ was not declared in this scope
static constexpr auto _S_vtable = _S_apply();
请告诉我这里可能有什么问题
如评论中所述,这是当前 GCC 版本中的一个已知错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90943
一个简单的解决方法是使用 static_cast
.
强制 std::visit()
直接对变体而不是子类进行操作
std::visit(LexerTokenExtractor{string_token}, static_cast<TokenBase&>(id_token));
这是我的代码,可以很好地编译 clang,但在 gcc 中编译失败
#include <iostream>
#include <string>
#include <regex>
#include <variant>
struct Id {
void SetValue(const std::string& item)
{
value = item;
}
std::string value;
};
struct Number {
void SetValue(const std::string& item)
{
value = std::stoi(item);
}
int value;
};
using TokenBase
= std::variant<Number, Id>;
struct Token : TokenBase {
using TokenBase::TokenBase;
template <typename T>
[[nodiscard]] bool Is() const {
return std::holds_alternative<T>(*this);
}
template <typename T>
[[nodiscard]] const T& As() const {
return std::get<T>(*this);
}
template <typename T>
[[nodiscard]] const T* TryAs() const {
return std::get_if<T>(this);
}
};
struct LexerTokenExtractor {
const std::string& item_;
void operator()(Number& item) const {
item.SetValue(item_);
}
void operator()(Id& item) const {
item.SetValue(item_);
}
};
int main()
{
const std::string string_token("x");
Token id_token = Id();
std::visit(LexerTokenExtractor{string_token}, id_token);
std::cout << "ok" << std::endl;
}
这是日志:
required from here
/usr/include/c++/7/variant:97:29: error: incomplete type ‘std::variant_size<Token>’ used in nested name specifier
inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
/usr/include/c++/7/variant: In instantiation of ‘constexpr const auto std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>::_S_vtable’:
/usr/include/c++/7/variant:711:29: required from ‘struct std::__detail::__variant::__gen_vtable<void, LexerTokenExtractor&&, Token&>’
/usr/include/c++/7/variant:1255:23: required from ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = LexerTokenExtractor; _Variants = {Token&}]’
1673947047/source.cpp:65:57: required from here
/usr/include/c++/7/variant:711:49: error: ‘_S_apply’ was not declared in this scope
static constexpr auto _S_vtable = _S_apply();
请告诉我这里可能有什么问题
如评论中所述,这是当前 GCC 版本中的一个已知错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90943
一个简单的解决方法是使用 static_cast
.
std::visit()
直接对变体而不是子类进行操作
std::visit(LexerTokenExtractor{string_token}, static_cast<TokenBase&>(id_token));