提问人:kteperin 提问时间:8/15/2023 最后编辑:Jan Schultkekteperin 更新时间:8/15/2023 访问量:182
如何在 std::variant 中存储 std::string 或 std::string_view?
How to store either std::string or std::string_view in a std::variant?
问:
我正在研究词法分析器。我有一个结构,看起来像这样:Token
struct Token {
enum class Type { ... };
Type type;
std::string_view lexeme;
}
的只是完整源代码的一小部分视图(顺便说一句,这也是)。Token
lexeme
std::string_view
问题是我需要重新映射特殊字符(例如,)。按原样存储它们不是一个好的解决方案。'\n'
我试过用 替换 的类型,但它很快就变成了意大利面条代码,因为每次我想读取词素(例如,检查类型是否是和词素是)时,这都是一个很大的痛苦。lexeme
std::variant<std::string, std::string_view>
Bool
"true"
存储为所属字符串并不能解决问题。lexeme
顺便说一下,我使用 C++20;也许有一个很好的解决方案?
答:
在我看来,您所需要的只是封装变体,以便为两者提供统一的接口。由于将 an 转换为 an 非常便宜,复制 an 同样便宜,您可以为此创建一个方法并访问这样的内容。std::string
std::string_view
std::string_view
struct OptOwnString
{
using variant_t = std::variant<std::string, std::string_view>;
variant_t value;
std::string_view view() const noexcept
{
/**
* Note: noexcept since it is effectively impossible to
* make this particular variant valueless_by_exception
*/
return std::visit([](auto const& v) {
return std::string_view(v); }, value);
}
};
int main()
{
OptOwnString owning { std::string("foo") };
std::cout << owning.view() << '\n';
OptOwnString borrowed { owning.view() };
std::cout << borrowed.view() << '\n';
}
评论
view()
可以是 ,并且为了减少发出的代码大小,可以使用 。const noexcept
*std::get_if<std::string_view>(value)
view
return std::visit([](auto const& v) { return std::string_view(v); }, value);
static_cast
std::visit(static_cast_<std::string_view>, value)
你可以直接使用std::string
首先,a 可以和 .这可能没有您想象的那么昂贵,因为在所有 C++ 标准库中都有 SSO(小字符串优化)。std::string
Token
std::string_view
std::string
这意味着短令牌不会在堆上分配;这些字符将直接存储在容器中。在讨论 和 之前,您可能希望衡量分配是否甚至是一个性能问题。否则,这是一个过早优化的情况。"const"
std::string_view
std::variant
如果你坚持......std::variant
用户@Homer512已经提供了一个可靠的解决方案。您可以围绕它创建一个包装器,而不是直接使用 ,它为 和 提供类似字符串的接口。std::variant
std::string
std::string_view
这很容易做到,因为大多数成员函数的名称和含义对于这两个类都是相同的。这也使它们易于通过 std::visit
使用。
struct MaybeOwningString
{
using variant_type = std::variant<std::string, std::string_view>;
using size_type = std::string_view::size_type;
variant_type v;
// main member function which grants access to either alternative as a view
std::string_view view() const noexcept {
return std::visit([](const auto& str) -> std::string_view {
return str;
}, v);
}
// various helper functions which expose commonly used member functions
bool empty() const noexcept {
// helper functions can be implemented with std::visit, but this is verbose
return std::visit([](const auto& str) {
return str.empty();
}, v);
}
size_type size() const noexcept {
// helper functions can also be implemented by using view()
return view().size();
}
// ...
};
评论
std::string
std::string_view
std::visit
std::variant<std::string, std::string_view>
std::variant
std::string_view
std::string_view
std::string
std::string