在我的代码中,我检查以查看对象是否为空/空.
有没有办法将对象设置为null?
我想存储一个不平凡的类型,它是不可移动且不可复制的std::optional。然而该对象是由自由函数构造的。(例子)
struct Foo {
Foo();
Foo(Foo const&) = delete;
Foo(Foo&&) = delete;
Foo& operator=(Foo const&) = delete; // added for completeness
Foo& operator=(Foo&&) = delete; // added for completeness
~Foo();
};
Foo foo();
Run Code Online (Sandbox Code Playgroud)
无需改变Foo或foo();
感谢复制省略,我已经可以做到这一点:
Foo f1 = foo();
Run Code Online (Sandbox Code Playgroud)
这也可以编译,因为std::optional只要求存储的类型是可破坏的:
std::optional<Foo> f2;
f2.emplace();
Run Code Online (Sandbox Code Playgroud)
但我无法填写f2函数结果:
f2 = foo(); // no
f2.emplace(foo()); // no
Run Code Online (Sandbox Code Playgroud)
显然,因为这需要复制或移动Foo. 这可能是不可能的,但我是否忽略了一些事情?
在cppreference上,我们可以看到std::optional采用默认值U&&而不是T&&。
它使我无法编写以下代码:
std::optional<std::pair<int, int>> opt;
opt.value_or({1, 2}); // does not compile
opt.value_or(std::make_pair(1, 2)); // compiles
Run Code Online (Sandbox Code Playgroud)
但是,我发现使用 没有任何好处U&&,因为U必须可以转换为T此处。
所以,考虑下面的代码,如果我们有一些U不同于 的类型T,那么就不会有完美的匹配。然而,通过执行隐式转换,我们仍然可以解析我们的调用:
template< class U >
constexpr T value_or( T&& default_value ) const&;
Run Code Online (Sandbox Code Playgroud)
我有以下代码来测试模板函数是否可以接受需要额外隐式转换才能完美匹配的参数,并且它可以编译:
#include <cstdio>
#include <optional>
#include <map>
struct A {
int i = 1;
};
struct B {
operator A() const {
return A{2};
}
};
template <typename T>
struct C { …Run Code Online (Sandbox Code Playgroud) 注意:这个问题被简要标记为this的重复,但它不是一个完全重复的,因为我专门询问 std::optionals 。如果您关心一般情况,仍然是一个值得阅读的好问题。
假设我有嵌套的选项,像这样(愚蠢的玩具示例):
struct Person{
const std::string first_name;
const std::optional<std::string> middle_name;
const std::string last_name;
};
struct Form{
std::optional<Person> person;
};
Run Code Online (Sandbox Code Playgroud)
和这个垃圾邮件功能:
void PrintMiddleName(const std::optional<Form> form){
if (form.has_value() && form->person.has_value() && form->person->middle_name.has_value()) {
std::cout << *(*(*form).person).middle_name << std::endl;
} else {
std::cout << "<none>" << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
展平此可选检查的最佳方法是什么?我做了这样的东西,它不是可变参数,但我不太关心(membr3如果真的有必要,我可以再添加一个级别(用 重载),除此之外的一切都是糟糕的代码)。
template<typename T, typename M>
auto flatten_opt(const std::optional<T> opt, M membr){
if (opt.has_value() && (opt.value().*membr).has_value()){
return std::optional{*((*opt).*membr)};
}
return decltype(std::optional{*((*opt).*membr)}){};
}
template<typename T, typename M1, typename M2> …Run Code Online (Sandbox Code Playgroud) 当切换到c ++ 17并用std::optional标准解决方案替换自定义解决方案时,检测到clang 5的一个非常奇怪和意外的行为.出于某种原因,emplace()由于对std::is_constructible参数类的特征的错误评估而被禁用.
在复制之前必须满足一些特定的前提条件:
#include <optional>
/// Precondition #1: T must be a nested struct
struct Foo
{
struct Victim
{
/// Precondition #2: T must have an aggregate-initializer
/// for one of its members
std::size_t value{0};
};
/// Precondition #3: std::optional<T> must be instantiated in this scope
std::optional<Victim> victim;
bool foo()
{
std::optional<Victim> foo;
// An error
foo.emplace();
/// Assertion is failed
static_assert(std::is_constructible<Victim>::value);
}
};
Run Code Online (Sandbox Code Playgroud)
更改任何前提条件并按预期编译.标准中是否存在一些未知的不一致性,使得clang在符合要求时拒绝此代码?
作为旁注:GCC 7.1 …
是否有可能以std::optional::value_or(expr)懒惰的方式评估参数,所以expr仅在没有值的情况下计算?
如果没有,什么是适当的替代品?
std::variant可以进入一种称为“ 异常无价值 ”的状态。
据我了解,这是导致移动分配抛出异常的常见原因。不能保证该变体的旧值不再存在,预期的新值也不是。
std::optional,但是没有这种状态。cppreference提出了大胆的主张:
如果引发异常,则* this ...的初始化状态不变,即,如果对象包含一个值,则它仍然包含一个值,反之亦然。
如何std::optional避免变得“异常无价值”而std::variant不能避免?
实际上如何从可选项中获取值?意思是取得 中的值的所有权std::optional并将其替换为std::nullopt(或将其交换为另一个值)?
例如,在 Rust 中,您可以.unwrap执行Option或执行类似的操作foo.take().unwrap()。我正在尝试用 C++ 做类似的事情optional。
C++23 添加了一些关于可选值的“monadic-style”功能,作为以下方法optional<T>:
optional<T>::and_then()(并忽略 的限定符this):
Run Code Online (Sandbox Code Playgroud)template<class F> constexpr auto and_then(F&& f);返回对包含的值(如果存在)调用 f 的结果。否则,返回返回类型的空值。
optional<T>::transform()(并忽略 的限定符this):
Run Code Online (Sandbox Code Playgroud)template<class F> constexpr auto transform(F&& f);如果包含一个值,则返回一个包含对所包含值
std::optional调用的结果的。否则,返回此类类型的空值。f*thisstd::optional
那么,这两个函数不是在做同样的事情吗?
c++ ×10
stdoptional ×10
c++17 ×5
c++23 ×2
monads ×2
c++20 ×1
copy-elision ×1
is-empty ×1
null ×1
object ×1
option-type ×1
std-variant ×1
stl ×1