【问题标题】:In class initialization and initializer list在类初始化和初始化列表中
【发布时间】:2013-10-18 14:33:29
【问题描述】:

我最近发现你不能同时在类初始化和初始化列表中。 以下代码失败:

struct s
{
    int i=0;    
};
int main() {
    s s1; //s1.i = 0
    //s s2={42}; //fails
    return 0;
}

如果我删除类中的初始化,初始化列表就可以正常工作!

有人可以解释一下为什么不允许这样的事情吗?

【问题讨论】:

  • 你确定你是在 C++11 模式下编译吗?编译器真的实现了吗?你有哪个编译器和它的什么版本?

标签: c++ c++11 initializer-list in-class-initialization


【解决方案1】:

事实上,这在 C++14 中是允许的。

struct s
{
    int i=0;    
};

int main() {
    s s1;
    s s2 = {42}; // succeeds
}

您的编译器很可能没有在 C++14 中实现新规则。然而,最新版本的 clang 接受了这一点,并在 C++14 模式下做了正确的事情。

当类内初始化被添加到 C++11 时,它被指定为防止类成为聚合。这样做是因为当时聚合概念与需要简单可构造的 PoD 类型密切相关。具有类内初始化意味着类型不再是可简单构造的。然而,从那时起,这两个概念变得更加独立,因此对于 C++14,接受了一个简短的提议来扭转这一决定。

【讨论】:

  • GCC 4.8 没有。
  • 我认为它在 C++11 中是不合法的。看我的回答。
  • @thokra 我原以为它在 gcc 4.9 中,但它也不存在。
  • @bames53:啊,C++14 ......现在我们正在谈论。 ;)
  • 我知道它已被选为答案,但这不是回答问题。
【解决方案2】:

这个初始化:

s s1 = { 42 };

要求s 是一个聚合,或者它有一个有效的构造函数,例如一个int 或一个std::initializer_list

当您在声明点添加成员初始化时,会将您的类 s 呈现为非聚合,因此您不能再使用聚合初始化。

您可以通过添加构造函数为您的非聚合使用相同的初始化语法

struct s
{
    s(int i) : i(i) {}
    int i=0;    
};

我相信 C++14 已经放宽了这个限制。

更多信息请参见What are aggregates...

【讨论】:

  • 这不是解释。问题是为什么聚合的成员可能没有大括号或相等的初始值设定项。
  • @VladfromMoscow 因为标准是这样说的。那里没有任何解释,但我猜人们意识到取消 C++14 的这条规则是足够安全的。
  • 我也遇到过这种解决方法,但这正是我想要避免的
  • @CômeDavid 我明白了。我并不是建议将其作为一种解决方法,只是试图展示如何使用聚合初始化语法构造非聚合。
猜你喜欢
  • 2023-03-13
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多