我有一个函数backend
,它可以加载给定页面或所有页面(如果是load(std::optional<int> page)
)。因为加载是一项昂贵的操作,所以我缓存了最后加载的页面及其内容。为此,我正在使用类型为page.empty()
的成员变量,其值应告诉我当前是缓存单个页面,所有页面还是根本没有页面。
LLVM的libc ++实现(与clang std::optional<std::optional<int>>
一起提供)在比较std :: optional实例时具有令人惊讶的行为,这与Apple LLVM version 10.0.0 (clang-1000.11.45.2)
所做的不同(已通过1.67测试):
boost::optional
这是正确的行为,这是libc ++实现中的错误吗?
答案 0 :(得分:4)
行为正确:
https://en.cppreference.com/w/cpp/utility/optional/operator_cmp
template< class T, class U > constexpr bool operator!=( const optional<T>& lhs, const optional<U>& rhs ); (2)
对可选对象执行比较操作。
1-6)比较两个可选对象lhs和rhs。包含的值 仅当两个lh都被比较时(使用T的相应运算符) 和rhs包含值。否则,
当且仅当lhs和rhs都符合 不包含值。
std::optional<T>
的默认构造函数构造了一个不包含值的对象,因此std::optional<int>>()
和std::optional<std::optional<int>>()
都不包含值,因此它们相等。
答案 1 :(得分:2)
作为旁注(但由于我们一直在这里),我个人不太喜欢您的设计。作为您的代码的使用者,我希望load(<empty optional>)
可以加载...没有页面。这就是可选的含义。
一种解决方案是具有两种不同的功能:
void load(int);
void load_all();
如果这对于您来说太激进了,那么您可以通过以下几种方法来重载:
struct load_all{};
void load(int);
void load(load_all);
我真的很想明确我的要求和得到的东西。这就是为什么我强烈喜欢上面的方法而不是下一个解决方案的原因:
void load(int);
void load();
为了完整起见,尽管我实际上并不推荐这样做(因为与std::variant
配合使用的工具很繁琐,否则可以很好地表达其意图):
struct load_all{};
void load(std::variant<int, load_all>);
答案 2 :(得分:1)
这实际上是很有趣的……如果模棱两可,这种行为是友善的。比较应该应该做什么没有明确的答案。根据实现选择,标准库和Boost会做不同的事情。没有人是错的。
std::optional
具有混合的比较。这意味着有些运算符将optional<T>
与optional<U>
和U
进行比较。在此模型中,最佳匹配是将双方都视为可选-因此,由于双方均未接合,因此它们的比较是平等的。
但是boost::optional
仅具有相同的类型比较。意味着optional<T>
仅可与optional<T>
或T
相提并论。在此模型中,optional<int>
被解释为optional<optional<int>>
的 value 。因此,我们有一个脱节的可选值和一个值-因此它们比较不相等。
我不确定此比较是否具有明确的含义,因此最好避免使用它。