C++11 私有成员的聚合初始化,正确吗?

C++11 Aggregate initialization of private member, is it correct?

在将私有成员作为参数传递给所有者的 class 函数时,通过聚合初始化来初始化私有成员是否正确?看看下面的代码。

class A {
  struct S {
    int t, u;
  };
public:
  void f(const S& s) {}  
};

int main() {
  A a;
  a.f({1, 2}); // correct?
  return 0;
}

我查了standard和nets,好像没有确切的答案。看起来机制如下: * 大括号初始化器是 public 的东西,因此用户不会违反访问限制。 * 从初始值设定项到 "S" 的隐式转换对于 "S" 是内部的,因此对于编译器也很好。

问题是,在标准、草案或至少 cppreference 中是否有一些关于此行为描述的参考?

是的,这是正确的。 S 唯一不公开的是名字。访问控制仅通过名称 ([class.access]p4). So you could use a type trait to get the type of S for example through f's type (example) 来控制访问。

所以,这是允许的,因为没有限制 [dcl.init.agg] 禁止初始化 "private" 类型。

还有 a note,由@StephaDyatkovskiy 找到。

官方是否有效并不重要;你应该避免这种极端情况。

我会说 "is it valid C++" 是错误的问题。

当您查看一段代码并尽可能尝试时,您无法决定它是否应该是有效的 C++;并且您知道这将是一些极端情况,具体取决于标准的确切措辞 - 无论哪种方式,通常都不要依赖该极端情况通常是个好主意。为什么?因为其他人也会感到困惑;他们会浪费时间去理解你的意思;他们会在标准中查找它——或者更糟的是,不查找它,并做出无效的假设;他们会从他们真正需要关注的事情上分心。

所以,使用这段代码,我会问自己:"Is type S really private? Does outside code really not need to know about it?"

如果答案是 "Yes, it is" - 那么我会更改 f,以获取 S 构造函数的参数(并将它们转发给 ctor):

void f(int t, int u) { S {t, u}; /* etc. etc. */ }

如果答案是 "No, code calling f() can know that it's passing an S reference" - 那么我会 S public.