- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图理解类型特征传播背后的机制,如 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r4.html 中 std::optional 所述.复制操作的处理有细微的差别,复制操作应有条件地定义为删除,而移动操作则不应参与重载决议。
这种差异的原因是什么,我将如何测试后者?例子:
#include <type_traits>
#include <optional>
struct NonMoveable {
NonMoveable() = default;
NonMoveable(NonMoveable const&) = default;
NonMoveable(NonMoveable&&) = delete;
NonMoveable& operator=(NonMoveable const&) = default;
NonMoveable& operator=(NonMoveable&&) = delete;
};
// Inner traits as expected
static_assert(!std::is_move_constructible<NonMoveable>::value);
static_assert(!std::is_move_assignable<NonMoveable>::value);
// The wrapper is moveable, via copy operations participating in
// overload resolution. How to verify that the move operations don't?
static_assert(std::is_move_constructible<std::optional<NonMoveable>>::value);
static_assert(std::is_move_assignable<std::optional<NonMoveable>>::value);
int main(int argc, char* argv[])
{
NonMoveable a1;
NonMoveable a2{std::move(a1)}; // Bad, as expected
std::optional<NonMoveable> b1;
std::optional<NonMoveable> b2{std::move(b1)}; // Good, see above. But
// useless as a test for
// P0602R4.
return 0;
}
奖金问题
error: use of deleted function 'std::optional<NonMoveable>::optional(std::optional<NonMoveable>&&)'
根据
Why do C++11-deleted functions participate in overload resolution?在重载决议之后应用删除,这可能表明移动构造函数参与,尽管 P0602R4 表示不应。
... If these steps produce more than one candidate function, then overload resolution is performed ...
最佳答案
std::optional 是一个红鲱鱼;关键是了解导致为什么将这些要求放在库类型上的机制
There is a subtle difference in the treatment of copy operations, which shall be conditionally defined as deleted, versus move operations, which shall rather not participate in overload resolution.
std::optional
的底层要求(以及如何实现这些要求)很复杂。然而,移动操作不应参与重载决议(对于不可移动类型)与被删除的复制操作(对于不可复制类型)的要求可能与一个单独的主题有关;
std::optional
更简单的类型来理解这个主题。 .
struct A {
A() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
A(A const &) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
A &operator=(A const &) {
std::cout << __PRETTY_FUNCTION__ << "\n";
return *this;
}
};
struct B {
B() { std::cout << __PRETTY_FUNCTION__ << "\n"; }
B(B const &) { std::cout << __PRETTY_FUNCTION__ << "\n"; }
B &operator=(B const &) {
std::cout << __PRETTY_FUNCTION__ << "\n";
return *this;
}
B(B &&) = delete;
B &operator=(B &&) = delete;
};
哪里,
A
:
B
, 而且:
A getA() {
A a{};
return a;
}
B getB() {
B b{};
return b;
}
C++14
When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. [...]
This elision of copy/move operations, called copy elision, is permitted in the following circumstances:
- in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function's return value
- [...]
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the object to be copied is designated by an lvalue, or when the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
[..] Even when the creation of the temporary object is unevaluated (Clause [expr]) or otherwise avoided ([class.copy]), all the semantic restrictions shall be respected as if the temporary object had been created and later destroyed.
auto aa{getA()}; // OK, and copy most likely elided.
而以下是
格式错误 :
auto bb{getB()}; // error: use of deleted function 'B::B(B&&)'
因为重载决议会找到
B
的声明但已删除的移动构造函数在考虑
b
的步骤中在
return b;
在
getB()
作为右值。对于
A
,不存在移动构造函数,这意味着
a
的重载决议在
return a;
在
getA()
与
a
因为右值会失败,然后没有这个扭结的重载决议会成功找到
A
的复制构造函数(随后将被省略)。
When an object of class type X is passed to or returned from a function, if each copy constructor, move constructor, and destructor of X is either trivial or deleted, and X has at least one non-deleted copy or move constructor, implementations are permitted to create a temporary object to hold the function parameter or result object. The temporary object is constructed from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by using the non-deleted trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object).
getB()
执行复制省略。不通过返回值重载解析的特殊规则(之前选择了删除的移动构造函数),这样这两个在 C++17 中都是格式良好的:
auto aa(getA()); // OK, copy elided.
auto bb(getB()); // OK, copy elided.
C++20
// B as above
B getB() {
B b{};
return b;
}
带有错误消息
error: use of deleted function 'B::B(B&&)'
B
的情况下,人们会期望在上面选择一个拷贝(可能被省略)。已经删除了它的移动 ctor。如有疑问,请确保移动构造函数和赋值运算符不参与(即存在)重载决议。
const
- 和引用限定符,比如
const A& operator=(const A&) const && = delete;
,这在重载解决方案期间很少成为可行的候选者(分配给
const
右值),并且可以保证不存在其他非常量和
&
- 限定的重载,否则可能是有效的重载候选者。
关于c++ - std::optional:不参与重载决议与被定义为已删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64153799/
tl;dr:我编写的函数创建了多个子进程,这些子进程在提交消息中的数据时解决 promise 。尽管该函数将所有这些 Promise 包装在 Promise.All 中,但该函数将突然返回,并且 Pr
我目前正在阅读 Jon Skeet 的 C# in depth 第 2 版,我想到了以下问题: 编译器如何能够在 list.Sort(Comparison) 之间进行选择?和 list.Sort(My
我是一名优秀的程序员,十分优秀!