需要帮助了解"{}-initializer syntax minimizes the chances for unfortunate conversions"



在"C++编程语言"第4版第164页:

当我们明确提到要初始化的对象的类型时,我们有两种类型需要考虑:对象的类型和初始化器。例如:

char v1 = 12345; // 12345 is an int
int v2 = 'c'; // 'c' is a char
T v3 = f();

通过对此类定义使用{}-初始值设定项语法,我们将不幸转换的机会:

char v1 {12345}; // error : narrowing
int v2 {'c'}; // fine: implicit char->int conversion
T v3 {f()}; // works if and only if the type of f() can be implicitly converted to a T

我不太理解句子minimize the chances for unfortunate conversions和对T v3 {f()};的注释works if and only if the type of f() can be implicitly converted to a T。考虑以下两种情况:

  • a)如果T有一个采用f()类型参数的显式构造函数
  • b) 如果f()的类型有一个到某种类型X的转换运算符,而T有一个接受X类型参数的构造函数

对于这两种情况,f()的类型都不能隐式转换为t,但T v3 {f()}的格式很好,所以至少该注释的only if部分似乎不合适?(也不确定if部分是否正确。)
对于这两种情况,都是T v3 = f();格式错误,那么minimize the chances for unfortunate conversions在这里是什么意思?似乎{}-初始值设定项实际上接受了更多的转换形式(是否不幸是另一个问题)。(在v1的情况下说明了防止变窄,这很清楚。我对v3感到困惑。)

它实际上以默认方式之外的其他方式进行转换。

使用您的一个示例,char x = 12345;实际上会将这个值减少到最后8位,因为这是char的大小。用{}表示法,由于它不接近,所以会产生误差。

有时(ab)并不是用来获得特殊效果的,所以在新的C++中,它被保留为默认选项,而新的符号用于提供更好的行为,同时减少错误空间。

转换:

char v1 = 12345;

不幸,因为它几乎肯定不是程序员想要的:

  • 要么我们想要一个可以表示值12345的类型
  • 或者我们使用了正确的类型,但使用了错误的值

对于v3,同样适用,但适用于更复杂的上下文。第一个代码段将强制编译器考虑用户定义的转换序列。这增加了出错的可能性;毕竟,我们可能会错误地实现转换运算符,造成拼写错误,或者设法在方孔中安装一个圆形销钉。使用复制列表初始化,我们排除了用户定义的转换序列,使转换更加安全。

有关为什么会发生这种情况的示例和详细解释,请参阅此问题。

v3初始化注释:

T v3 {f()}; // works if and only if the type of f() can be implicitly converted to a T

不是严格正确的。当且仅当f()的类型可以显式转换为T时,该初始化才有效。此语法:

T v3 = {f()}; // truly does work if and only if the type of f()
// can be implicitly converted to a T

(复制列表初始化而不是直接列表初始化)确实需要隐式转换。这个程序说明了区别:

struct T {
explicit T(int) {}
};
int f() { return 0; }
int main() {
T v3 = {f()};
}

其中初始化将被诊断为格式错误,因为它为T(Coliru的实时演示)选择了一个显式构造函数。

最新更新