内联使用成员对象的非默认显式构造函数

Posted

技术标签:

【中文标题】内联使用成员对象的非默认显式构造函数【英文标题】:Inline use of non-default explicit constructor for a member object 【发布时间】:2016-01-06 03:59:40 【问题描述】:

在 C++11(或未来)中,是否存在以下合法的一些简单变体?

class A
   
public:
   std::vector<char> b(123); // declare a vector with 123 elements
   ;

我能找到的最接近的有点笨拙,而且可能效率低下......

class A
   
public:
   std::vector<char> b = std::vector<char>(123);
   ;

我试图避免使用初始化列表。我更喜欢将b 的声明和初始化合并到一行代码中。向量的大小始终相同。

我在这个例子中使用std::vector,但大概答案会更普遍适用。


为了更好地衡量,这是来自gcc 4.8 版的错误消息:

错误:数字常量之前的预期标识符 标准::向量 b(123);

这是来自clang 3.7 版的消息:

错误:预期的参数声明符 标准::向量 b(123);

【问题讨论】:

std::vector&lt;char&gt; b = decltype(b)(123); 不那么笨重了吗? @RSahu:我喜欢这样。这是一种改进——减少了冗余。 您可以期待现代编译器的省略 - 有关概述,请参阅 copy_elision on cpprefrence “向量的大小始终相同。” - 如果您没有其他理由特别想要vector,可以考虑std::array&lt;char, 123&gt; b; @nobar 如果您不能信任基本省略,那么为什么要相信 int x = 1+1; 不会向 google 发送网络请求以仔细检查数学? (根据标准,这是可选的——即允许的)。一个糟糕的编译器会主动生成糟糕的代码,比如在简单的情况下无法省略,这是一个偏执的问题。我知道完全零个无法忽略的 C++11 编译器(除非疯狂的编译器设置) 【参考方案1】:

极不可能。最初允许 NSDMI 的提案首先解决了这个问题:

N2756

在 Kona 中提出的关于标识符范围的问题:

在 07 年 9 月核心工作组的讨论中 在 Kona 的会议上,出现了一个关于标识符的范围的问题 初始化器。我们是否希望允许类范围有可能 正向查找;还是我们想要要求初始化器是 在解析它们时定义明确?

想要什么:

类范围查找的动机是我们希望能够 在非静态数据成员的初始化器中放入任何我们可以使用的东西 在不显着改变语义的情况下放入 mem-initializer (模直接初始化与复制初始化):

int x();

struct S 
    int i;
    S() : i(x())  // currently well-formed, uses S::x()
    // ...
    static int x();
;

struct T 
    int i = x(); // should use T::x(), ::x() would be a surprise
    // ...
    static int x();
;

问题一:

不幸的是,这使得“( expression-list )”的初始化器 在解析声明时形成歧义:

...

提案:

CWG 在 Kona 进行了 6 比 3 的投票,支持类范围查找; 这就是本文的建议,使用非静态初始化器 数据成员限于“= initializer-clause”和“ initializer-list ”表单。我们相信:

问题 1:这个问题不会发生,因为我们没有提出 () 符号。 = 初始值设定项符号不受此影响 问题。

除非您的编译器不使用复制省略(所有主要的编译器都使用),否则这种笨拙的初始化方式并没有什么低效的地方。问题是 C++ 的语言设计者已经把自己逼到了一个角落。因为初始化列表构造函数是 greedy,大括号初始化将构造一个带有给定 elements 的向量,而使用括号的旧语法调用显式构造函数来设置大小。

除非您不能在 NSDMI 中使用该构造函数。除非你使用等号。

如果由于某种原因让您感到困扰,有一些笨拙的解决方法:

std::vector<char> c = decltype(c)(123);
// ...
using VChar = std::vector<char>;
VChar v = VChar(123);

或者意识到新功能并不排除现有功能:

std::vector<char> c;

A() : c(123)


【讨论】:

以上是关于内联使用成员对象的非默认显式构造函数的主要内容,如果未能解决你的问题,请参考以下文章

C++调用父类的构造函数规则

9——对象的创建和撤销,构造函数和析构函数

10.对象和类

c++之构造函数,析构函数(五千字长文详解!)

C++类和对象中

使用显式定义的默认构造函数将 unique_ptr 的类内成员初始化程序设置为 nullptr 错误