c++ - 我认为 N4140 §8.5[dcl.init]/17 中的要点 (17.6.2) 可能有一点不准确

标签 c++ initialization language-lawyer c++14

在 N4140 的 §8.5[dcl.init]/17 中的要点 (17.6.2) 中,我们有(重点是我的):

Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3). If the conversion cannot be done or is ambiguous, the initialization is ill-formed. The function selected is called with the initializer expression as its argument; if the function is a constructor, the call initializes a temporary of the cv-unqualified version of the destination type. The temporary is a prvalue. The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see 12.2, 12.8.

粗体文本部分似乎表明直接初始化永远不会调用用户定义的转换序列。但这不是我在下面发现的:

#include <iostream>

struct A {
    A() { std::cout << "default ctor A" << '\n'; }
    A(const A&) { std::cout << "copy A" << '\n'; }
};

struct C {
    C() { std::cout << "default ctor C" << '\n'; }
    operator A() { std::cout << "C::operator A()" << '\n'; return A(); };
};

int main()
{
     C c;
     A a{c};        // direct-initialization where the C::operator A() is invoked
                    // to copy construct the object `a`.
}

此片段打印以下内容:

default ctor C
C::operator A()
default ctor A
copy A
copy A

参见live example

编辑

回应@Johannes答案,请考虑 A a(c); 而不是 A a{c};。据我所知,其余部分仍然有效。

最佳答案

在讨论直接初始化时(重点是我自己的):

If the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source type is the same class as, or a derived class of, the class of the destination, constructors are considered. The applicable constructors are enumerated (13.3.1.3), and the best one is chosen through overload resolution (13.3). The constructor so selected is called to initialize the object, with the initializer expression or expression-list as its argument(s). If no constructor applies, or the overload resolution is ambiguous, the initialization is ill-formed.

此行通向有关重载解决方案的§8.5 (2.8,2.9)部分,该部分描述了该过程。

Overload resolution selects the function to call in seven distinct contexts within the language:

... (2.4) — invocation of a constructor for direct-initialization (8.5) of a class object...

But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:

(2.8) — First, a subset of the candidate functions (those that have the proper number of arguments and meet certain other conditions) is selected to form a set of viable functions (13.3.2).

(2.9) — Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.

鉴于上述情况,直接初始化实际上确实经历了选择候选构造函数(在您的情况下,单参数构造函数 A::A( A const &) )并查找隐式构造函数的过程反转序列将两者匹配在一起 - 即运算符 C::A()

他们在文本中对其他复制初始化案例应用了看似冗余的语言,这有点误导。

隐式转换序列上的额外语言 - 您在问题中引用 - 对于 (17.6.2) 的其他复制初始化情况直接引用以下情况:

class B {
    operator A();
};
class A {

};

B b;
A a = b;

这没有包含在(17.6.1)中的第一点中,因为B不是从A派生的,也不是任何存在有用的构造函数。因此它属于“其他”条款。

关于c++ - 我认为 N4140 §8.5[dcl.init]/17 中的要点 (17.6.2) 可能有一点不准确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33242948/

相关文章:

c++ - 在不同的命名空间中调用别名声明的基类构造函数

c++ - 使用 qt 和 django 创建桌面应用程序

c++ - 删除了默认构造函数。仍然可以创建对象......有时

c++ - std::is_unsigned<bool>::value 定义是否明确?

C++ - 声明函数 'static' 与形式 'const int function_name() const'

c++ - 具有 cmath 函数的 STL 方法

super 初始化后JavaFx调用 super 方法

c++ - C++14 中的统一初始化双分配给浮点变量不会产生缩小错误

c - 当定义和声明分开时,如何一次性初始化数组的所有元素?

c++ - C++ 中用户定义的文字命名