c++ - 对 std::variant 中保存的类型调用 << 运算符?
问题描述
我有一个这样的结构:
// Literal.hpp
struct Literal
{
std::variant<
std::nullptr_t,
std::string,
double,
bool
>
value;
friend std::ostream &operator<<(std::ostream &os, Literal &literal);
};
我正在尝试像这样实现 << 运算符:
// Literal.cpp
Literal::Literal() : value(value) {}
std::ostream &operator<<(std::ostream &os, const Literal &literal)
{
std::visit(/* I don't know what to put here!*/, literal.value);
}
我试过像这样实现运算符(注意:我会采用任何优雅的解决方案,它不一定是下面这个实现的解决方案)
// In Literal.cpp
std::ostream &operator<<(std::ostream &out, const Literal literal)
{
std::visit(ToString(), literal.value);
return out;
}
struct ToString; // this declaration is in literal.hpp
void ToString::operator()(const std::nullptr_t &literalValue){std::cout << "null";}
void ToString::operator()(const char &literalValue){std::cout << std::string(literalValue);}
void ToString::operator()(const std::string &literalValue){std::cout << literalValue;}
void ToString::operator()(const double &literalValue){std::cout << literalValue;}
void ToString::operator()(const bool &literalValue){std::cout << literalValue;}
但是在我的主函数中,传递一个 char 数组文字不会在它运行时将其转换为布尔值!忽略带字符的运算符重载:
main() {
Literal myLiteral;
myLiteral.value = "Hello World";
std::cout << myLiteral << std::endl;
}
解决方案
这是您的标准库中的错误。大概您正在使用 libstc++(GNU C++ 标准库),因为这就是 Godbolt 所显示的混乱。如果您使用 libc++(Clang/LLVM 的 C++ 标准库)进行编译,这将按预期工作。根据std::vector<Types...>::operator=(T&& t)
cppreference 页面,它
如果同时存在范围内的每个from Types...的虚构函数的重载,则确定
T_j
将由重载决议为表达式选择的替代类型,但以下情况除外:F(std::forward<T>(t))
F(T_i)
T_i
仅当声明对某些发明变量有效
F(T_i)
时才考虑重载;T_i x[] = { std::forward<T>(t) };
x
If
T_i
is (possible cv-qualified)bool
,F(T_i)
仅考虑 ifstd:remove_cvref_t<T>
is alsobool
。
最后一个条款就是针对这种情况的。因为很多东西都可以转换为bool
,但我们通常不打算进行这种转换,所以该子句会导致通常不会被选中的转换序列被选中(char const*
tobool
是标准转换,但 tostd::string
是“用户定义的”,即通常被认为是“更糟”)。你的代码应该设置value
为它的std::string
替代,但是你的库的实现std::variant
被破坏了。可能已经打开了一张问题票,但如果没有,这是打开一张的理由。如果你被你的库困住了,明确地将文字标记为 astd::string
应该可以工作:
literal.value = std::string("Hello World");
对于优雅的问题,使用缩写模板 lambda。
std::ostream &operator<<(std::ostream &os, Literal const &literal)
{
std::visit([](auto v) { std::cout << v; }, literal.value);
// or
std::visit([](auto const &v) {
// gets template param vvvvvvvvvvvvvvvvvvvvvvvvv w/o being able to name it
if constexpr(std::is_same_v<std::decay_t<decltype(v)>, std::nullptr_t>) {
std::cout << "null";
} else std::cout << v;
}, literal.value);
// only difference is nullptr_t => "nullptr" vs "null"
return std::cout;
}
此外,您的friend
声明与定义不符。实际上,无论如何都不应该friend
编辑它,因为它不需要访问private
成员。
// declaration in header, outside of any class, as a free function
std::ostream &operator<<(std::ostream&, Literal const&);
// was missing const ^^^^^
推荐阅读
- rally - 回溯 API 显示自定义字段的旧字段名称
- c# - 在 Facebook 页面上自动发布照片
- javascript - 如何使用js根据div的大小计算字体大小
- python - 给定像素标签,在python中绘制一个边界框
- python - 我怎样才能让这个正方形在 PyGame 中左右移动
- ios - Swift 中的泛型选择器视图
- python - 字符(音节)在枕头中未按正确顺序呈现
- reactjs - Redux - 如何调用一个动作并等待它解决
- wordpress - 显示特定用户自定义个人资料页面的评论
- vue.js - 如何编写一个服务工作者和 vue 组件都可以使用的全局函数?