我正在编写一个小型 C++11 库,我相信std::optional它会是一些可以返回nullptr. 然而,std::optional这是 C++17 的功能。由于 C++11 是一项要求,因此我正在寻找在std::optional保持兼容性的同时使用的方法。
我发现功能宏可以测试。我想我可以用它来检测是否std::optional可用......但是当它不可用时最好的方法是什么?
我应该提供自己的std::optional实现吗?
不可用nullptr时返回?std::optional(可能会弄乱我的代码。)
还是放弃这个想法,nullptr只继续返回?
我在互联网上看了几部在线 std::Optional 纪录片。但是我无法找到以下两个案例之间的任何直接比较:
情况1:
SomePointer* foo::get_some_pointer(cont int value) {
auto result = myMap.find(value);
if (result != myMap.end()) {
return const_cast<SomePointer*>(&result->second);
}
return nullptr;
}
Run Code Online (Sandbox Code Playgroud)
案例2
std::optional<SomePointer*> foo::get_some_pointer (cont int value) {
auto result = myMap.find(value);
if (result != myMap.end()) {
return std::optional<SomePointer*>{&result->second};
}
return std::nullopt;
}
Run Code Online (Sandbox Code Playgroud)
情况 1 相对于情况 2(nullopt 优于 nullptr)有哪些优点/缺点?
foo.value_or(bar())我在代码中使用时遇到了麻烦,因为我不希望当可选变量有值bar()时调用该函数。foo我发现这个问题解释了value_or()不使用惰性求值。
现在我想知道为什么会这样,惰性求值一直是 C 和 C++ 中条件语句的标准方面。我发现这非常违反直觉,我认为我不是第一个也不会是最后一个被它绊倒的人。由于存在要求了解设计者想法的风险std::optional,是否有一个用例可以解释为什么惰性评估在这里不是一个好主意?
我正在简单地阅读参考文献,并进入了讨论使用可选参考文献的部分。赫伯给出避免的原因之一optional<T&>是因为这些情况可以“同样很好地代表optional<not_null<T*>>”
我很困惑你什么时候会想要optional<not_null<T*>>。在我看来,optional取消已经结束了not_null,那么在这种情况下为什么不直接使用原始指针呢?
我刚刚看了cppcon谈论Bloomberg数据,这种变体类型使用IEEE754格式的冗余来编码存储在数据中的类型.
所以我想知道C++标准是否允许实现通过使用相同的技巧更有效地实现std :: optional.
请注意,这将要求有时存储在optional中的double的二进制表示与传递给构造函数的double的二进制表示不匹配.
注意:我关心标准允许这个与否,我知道大多数/所有实现都不会打扰.
我知道IEEE754不是标准规定的,但它是允许的,并且可以通过实现来检查.
我有以下代码来测试我的 constexpr 可构造惰性类:
#include <optional>
template <class T>
class Lazy
{
using initializer_t = T (*)();
std::optional<T> m_val = std::nullopt;
initializer_t m_initializer;
public:
constexpr Lazy(initializer_t initializer = initializer_t{[] { return T{}; }}) noexcept
: m_initializer{initializer} {}
T& operator*()
{
if (!m_val.has_value()) {
m_val = m_initializer();
}
return *m_val;
}
constexpr T* operator->() { return &(**this); }
};
#include <iostream>
struct A {
int f() { return 10; }
~A()
{
std::cout << "Goodbye A " << (void*)this << std::endl; …Run Code Online (Sandbox Code Playgroud) 假设我有一些基类,它可以选择返回一些特定的数据。它还为我提供了“hasData”函数来检查此类特定数据是否可供使用
class MyClassBase {
public:
virtual bool hasData() const { return false; }
virtual const Arg1& getData() const { throw std::runtime_error("No data"); }
};
class MyClassDerived: public MyClassBase {
Arg1 m_data = Arg1(10);
public:
bool hasData() const override { return true; }
// Good - no copy constructor for data as I want
const Arg1& getData() const override { return m_data; }
};
Run Code Online (Sandbox Code Playgroud)
这效果很好并且达到了我想要的效果。但是“hasData”和“getData”是很好的候选者,可以用一个返回“std::optional”的函数来替换。但是当我尝试改进返回 std::Optional 的 API 时,我意识到我无法再将“常量引用”返回到我的内部数据
class MyClassWithOptBase {
public:
virtual std::optional<Arg1> getData() const { return std::nullopt; } …Run Code Online (Sandbox Code Playgroud) std::move(*optional)和之间有有效的区别吗*std::move(optional)?哪一个更可取?
完整示例:
#include <optional>
#include <vector>
void foo()
{
std::optional<std::vector<int>> ov = std::vector<int>{};
std::vector<int> v;
v = std::move(*ov);
}
void bar()
{
std::optional<std::vector<int>> ov = std::vector<int>{};
std::vector<int> v;
v = *std::move(ov);
}
Run Code Online (Sandbox Code Playgroud) 查看以下代码作为示例:
#include <iostream>
#include <optional>
class A {
public:
A();
~A();
};
std::optional<A> a;
A::A() { std::cout << a.has_value(); }
A::~A() { std::cout << a.has_value(); }
int main() {
a.emplace();
std::cout << a.has_value();
}
Run Code Online (Sandbox Code Playgroud)
我最终得到了类似的东西,并且惊讶地发现它a在构造函数中没有价值。这可能是一件好事,因为该对象尚未完全构建并且我的设计可以改进。但我没有在 cppreference 中找到任何关于它应该按照标准表现的证据。
所以我的问题是(主要是出于好奇):上面示例代码中的输出应该是什么,是指定的还是实现定义的(或 UB)?
有趣的是,上面的代码打印(剧透):
010对于 GCC 和 Cland,以及011MSVC。
考虑以下代码:
#include <memory>
#include <optional>
template <typename T>
constexpr T * arg_to_pointer(T & arg) noexcept {
return std::addressof(arg);
}
int main() {
std::optional<int> foo;
auto * test = foo.transform(arg_to_pointer<int>).value_or(nullptr);
//auto * test = foo.transform(std::addressof<int>).value_or(nullptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
未注释掉的行(将一个哑包装器std::addressof作为函数参数传递给std::optional::transform)可以编译并正常工作。被注释掉的行(尝试std::addressof直接使用的行)没有 - 我收到一条错误,指示模板参数推导失败(此处使用 GCC 13.2 的实时示例,尽管在 Clang 16.0 中观察到类似的行为)。为什么是这样?std::addressof标准和我周围的愚蠢包装有什么区别?