c++ - 显式转换函数、直接初始化和转换构造函数

标签 c++ c++11 initialization type-conversion language-lawyer

后标准草案 n3376 有一个使用显式转换函数到用户定义类型的示例 (12.3.2:2):

class Y { };
struct Z {
  explicit operator Y() const;
};
void h(Z z) {
  Y y1(z); // OK: direct-initialization
}

根据 12.3.2:2,显式转换函数“仅被视为直接初始化的用户定义转换”;然而,这似乎允许:

struct Y { Y(int); };
struct Z {
  explicit operator int() const;
};
void h(Z z) {
  Y y1(z); // direct-initialization
}

这似乎与标准的意图冲突,并且确实被 gcc-4.7.1 拒绝:

source.cpp: In function 'void h(Z)':
source.cpp:4:9: error: no matching function for call to 'Y::Y(Z&)'
source.cpp:4:9: note: candidates are:
source.cpp:1:12: note: Y::Y(int)
source.cpp:1:12: note:   no known conversion for argument 1 from 'Z' to 'int'
source.cpp:1:8: note: constexpr Y::Y(const Y&)
source.cpp:1:8: note:   no known conversion for argument 1 from 'Z' to 'const Y&'
source.cpp:1:8: note: constexpr Y::Y(Y&&)
source.cpp:1:8: note:   no known conversion for argument 1 from 'Z' to 'Y&&'

gcc 拒绝通过 intZY 的转换是否正确,或者标准确实允许这种用法?

我考虑了提到的直接初始化的上下文;根据 8.5:16 中直接初始化为类类型的定义,使用初始化表达式作为参数调用构造函数,因此通过隐式转换序列 (13.3.3.1) 将其转换为参数类型。由于隐式转换序列是隐式转换 (4:3),因此模拟复制初始化 (8.5:14) 而不是直接初始化,因此 12.3.2:2 中的语言必须引用整个表达式。

另请注意,这并不违反 12.3:4(多个用户定义的转换);相同的编译器对删除了 explicit 的相同代码感到满意(Clang 和 Comeau 也是如此):

struct Y { Y(int); };
struct Z { operator int(); };
void h(Z z) {
  Y y1(z); // direct-initialization
}

我认为 Jesse Good 已经在 13.3.1.4:1 中确定了 operator Yoperator int 情况之间的区别,但是还有第三种情况我仍然关注者:

struct X {};
struct Y { Y(const X &); };
struct Z {
  explicit operator X() const;
};
void h(Z z) {
  Y y1(z); // direct-initialization via class-type X
}

要绑定(bind)到 Y 的构造函数的单个 const X & 参数的临时 X 的初始化直接进行 -根据 13.3.1.4:1 初始化上下文,TXSZ。我认为这个条款是不正确的,应该读作:

13.3.1.4 Copy-initialization of class by user-defined conversion [over.match.copy]

1 - [...] When initializing a temporary to be bound to the first parameter of a constructor that takes a reference to possibly cv-qualified T as its first argument, called with a single argument in the context of direct-initialization of an object of type "cv2 T", explicit conversion functions are also considered. [...]

为了避免混淆,我觉得12.3.2:2也应该修改一下:

12.3.2 Conversion functions [class.conv.fct]

2 - A conversion function may be explicit (7.1.2), in which case it is only considered as a user-defined conversion for direct-initialization (8.5) in certain contexts (13.3.1.4, 13.3.1.5, 13.3.1.6). [...]

对以上有什么意见吗?

最佳答案

根据 8.5 和 13.3.1.3,考虑了 Y 的构造函数,并通过重载决议选择最佳构造函数。在这种情况下,相关的构造函数是 Y(int); 以及复制和移动构造函数。在重载解析过程中 13.3.2 可行函数 [over.match.viable] 指定:

3 Second, for F to be a viable function, there shall exist for each argument an implicit conversion sequence (13.3.3.1) that converts that argument to the corresponding parameter of F. [...]

对于所有这些构造函数,不存在从 ZintY 的一种类型的这种转换。为了说服我们自己,让我们研究一下标准在 13.3.3.1 隐式转换序列 [over.best.ics] 中对隐式转换序列的说法:

1 An implicit conversion sequence is a sequence of conversions used to convert an argument in a function call to the type of the corresponding parameter of the function being called. The sequence of conversions is an implicit conversion as defined in Clause 4, which means it is governed by the rules for initialization of an object or reference by a single expression (8.5, 8.5.3).

如果我们交叉引用第 4 条,那么我们了解到隐式转换是根据复制初始化定义的(即 T t=e;,其中 Tintez):

(§4.3) An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed, for some invented temporary variable t (8.5). [...]

所以我认为 12.3.2:2 不申请 this 初始化,这发生在直接初始化的更大上下文中。否则会与最新的段落相矛盾。

关于c++ - 显式转换函数、直接初始化和转换构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12372442/

相关文章:

c++ - GCC/Clang 中内存对齐的通用属性

java - 从 Java 配置文件中读取配置参数的最佳方法是什么?

c++ - 使用用作 C++ 类型的 namespace

c++ - 无法使用迭代器删除 vector 元素, vector 元素实现移动构造函数

c++ - 多线程执行时间与随机数之和

c++ - C++ 中的默认结构初始化

java - 使用包括 block 初始值设定项的匿名类初始化静态 ArrayList 字段

C++ Qt 表达式 : _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) error

c++ - 如何找到样本信号在主信号中的位置?

c++ - 来自 {Python | 的远程过程调用 ruby | ...} 到 C++