【问题标题】:C++11 Aggregate initialization of private member, is it correct?C ++ 11私有成员的聚合初始化,是否正确?
【发布时间】:2019-05-14 08:00:35
【问题描述】:

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

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

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

我检查了标准和网络,似乎没有确切的答案。看起来机制如下: * 大括号初始化程序是公共的,因此用户不会违反访问限制。 * 从初始化程序到“S”的隐式转换对于“S”是内部的,因此也适用于编译器。

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

【问题讨论】:

  • 没关系。但是,如果您想要引用 C++ 标准的答案,请添加 language-lawyer 标签。
  • @StepanDyatkovskiy:A 不是聚合,因为 private 结构。
  • 建议您将其设为f(S),不要用创建临时文件的问题来混淆这个问题。
  • @P.W,但是“S”是一个集合,不是吗?
  • @StepanDyatkovskiy:是的,IMO 这应该可行。

标签: c++11 language-lawyer aggregate-initialization


【解决方案1】:

是的,这是正确的。关于S 唯一私密的就是名字。访问控制仅通过名称([class.access]p4)控制访问。因此,您可以使用类型特征来获取 S 的类型,例如通过 f 的类型 (example)。

因此,它是允许的,因为没有限制 [dcl.init.agg] 禁止初始化“私有”类型。

还有a note,由@StephaDyatkovskiy 发现。

【讨论】:

  • 但这怎么能不与“私人”的意思相矛盾呢?你能引用一下吗?
  • @einpoklum this 有帮助吗?它可能与直觉相反,但它就是这样工作的:只有当您命名类型时才会应用访问控制。
  • 有点。初始化对象并不涉及知道其类型/类型的名称,这一点并不明显。另外,请把它放在答案中;并记下我的回答。
  • @Rakete1111,根据您的参考资料,我找到了确切答案:eel.is/c++draft/class.access#5.sentence-2 您可以编辑您的答案,以便我接受吗?
  • @einpoklum 你认为你不能将 STL 与你自己的私有类型一起使用吗?
【解决方案2】:

是否正式有效无关紧要;你应该避免这种极端情况。

我会声称“它是有效的 C++”是错误的问题。

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

所以,有了这段代码,我会问自己:“S 类型真的是私有的吗?外部代码真的不需要知道吗?”

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

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

如果答案是“不,调用f() 的代码可以知道它正在传递S 引用” - 那么我会将S 公开。

【讨论】:

  • 您所说的一切都非常正确,但前提是您是您正在使用的所有代码的老板。
  • @StepanDyatkovskiy:我明白你的意思,但是: 1. 阅读这个问题的其他人没有这个问题。 2. 也建议您可以将代码转给拥有该代码的人。
猜你喜欢
  • 2015-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多