了解何时在()和{}初始化中通过类构造函数进行检查



据我所知,{}是一种用一些"安全";与其他方法相比的优势,例如禁止缩小:

int some_int_a = 1.2;  // narrows
int some_int_b (1.2);  // narrows
int some_int_c {1.2};  // does NOT compile, cannot narrow

到目前为止还不错。我最近发现的一件我不完全理解的事情是,这种检查什么时候发生?例如,在以下代码中:

#include <iostream>
class ExClass{
private:
const int i;
public:
ExClass(int i=0): i{i} {
// needed even if empty
}
void print(void){
std::cout << "const int i = " << i << std::endl;
}
};
int main(void)
{
ExClass ex_a (2.3);  // narrows! this was surprising to me, I (probably naively)
// expected i{i} in the constructor to forbid this.
ex_a.print();
ExClass ex_b {2.3};  // does not compile
ex_b.print();
return 0;
}

我想这意味着,在ex_a的情况下,首先通过缩小转换完全创建一个中间int,然后这个中间int用于在构造函数中对i进行括号初始化。而在第二种情况下,中间int不能用冲突的输入进行括号初始化,对吗?

有没有一种方法可以用这样一种方式来写东西;中间体";缩小,以便类括号初始化检测到错误的输入?

这里发生的是构造函数:

ExClass(int i=0): i{i}

采用int参数,并在此缩小范围:

ExClass ex_a (2.3);

很好。一旦进入构造函数,i就是int(参数,而不是成员(。因此,在i{i}中没有变窄(它是intint(。当您将构造函数更改为时,确实会出现错误

ExClass(double i=0): i{i} { }

因为现在CCD_ 13实际上正在缩小。

请注意,gcc只使用默认设置发出警告,并且需要-pedantic-errors将其识别为错误。感谢雷米指出这实际上是一个错误,而不是一个警告。

有没有一种方法可以用这样一种方式来写东西,即没有"中间体";缩小,以便类括号初始化检测到错误的输入?

您可以使构造函数采用模板参数,以便它采用调用方传入的任何类型,例如:

#include <iostream>
class ExClass{
private:
const int i;
public:
template<typename T>
ExClass(T i=T{}): i{i} {
// needed even if empty
}
void print(void){
std::cout << "const int i = " << i << std::endl;
}
};
int main(void)
{
ExClass ex_a (2.3);  // should not compile!
ex_a.print();
ExClass ex_b {2.3};  // should not compile!
ex_b.print();
return 0;
}

不幸的是,GCC默认情况下允许缩小范围,发出警告而不是错误(使用-pedantic-errors强制错误(:

警告:正在缩小"i"从"double"到"int"的转换[-Wstripping]

Clang发出错误,不过:

错误:类型"double"不能在初始值设定项列表中缩小为"int"[-Wc++11缩小]

Brace初始化(从C++11开始(防止缩小。作为下的cppreference状态缩小转换

列表初始化通过禁止以下行为:

从浮点类型到整数类型的转换
  • 从长双精度到双精度或到浮点的转换以及从双精度到浮点的转化,除非源是常量表达式并且不会发生溢出
  • 从整数类型到浮点类型的转换,除非源是可以存储其值的常量表达式正好在目标类型中
  • 从整数或无范围枚举类型转换为不能表示原始值的所有值的整数类型,除非source是一个常量表达式,其值可以精确地存储在目标类型
  • 从指针类型或指向成员类型的指针到布尔的转换(从C++20开始(
  • 因此,比起备选方案,更喜欢大括号初始化。

    调试器可能会很快向您显示这一点!看看你在做什么:if(ExClass(next(==false || opening_brackets_stack.empty((==false(

    当你试图将ExClass与近括号进行比较时,它的类型是什么

    提示:想想当你创建一个括号的每个新实例。它们都是括号吗?它们都是开括号的吗?

    最新更新