在外部类的公共构造函数调用中初始化内部私有类 - 标准的目的是什么?

Initialization of inner private class within public constructor call of outer class -What's the standard's intention for this?

提问人:Secundi 提问时间:2/15/2021 最后编辑:Secundi 更新时间:2/15/2021 访问量:62

问:

最近,我遇到了这样的代码:

class NeedsFactoryForPublicCreation
{
private:
    struct Accessor
    {
      // Enable in order to make the compile failing (expected behavior)
      // explicit Accessor() = default;
    };
 
public:
    explicit NeedsFactoryForPublicCreation(Accessor) {}
    
    // This was intended to be the only public construction way
    static NeedsFactoryForPublicCreation create()
    {
        NeedsFactoryForPublicCreation result{Accessor()};
        // ... Do something (complex parametrization) further on
        return result;
    }
};

int main()
{
    //NeedsFactoryForPublicCreation::Accessor publicAccessor {}; // Does not compile as expected
    NeedsFactoryForPublicCreation nonDefaultConstructible {{}}; // Compiles even with Accessor being an interal
}

起初,我有点震惊,这是编译的。 经过几分钟的分析(以及发生的自我怀疑......),我发现,由于访问说明符的定义以及编译器决定使用实际初始化方式的方式(聚合与公共构造函数查找),这是完全可以解释的。为了扩展第一个混淆,甚至这个访问类也是这样编译的:

class Accessor
{
    Accessor() = default; // private, but we are an aggregate...
    friend class NeedsFactoryForPublicCreation;
};

这又是完全可以解释的,因为 Accessor 仍然是一个聚合(另一个令人困惑的话题......

但为了强调,这个问题与聚合的细节无关(感谢 Jarod42 在评论中指出了即将到来的 C++20 更改!),这也编译了:

class Accessor
{
    public:
    Accessor() {}
    virtual ~Accessor() {}
    virtual void enSureNonAggregate() const {}
    friend class NeedsFactoryForPublicCreation;
};

并且不会在构造函数变为私有化时立即这样做。

我的问题:实际背景是什么,标准决定了访问说明符的效果,这有悖常理?与直觉相反,我特别指的是有效查找的不一致(只要我们保持未命名,编译器就不关心内部,但当涉及到实际的构造函数查找时,仍然完全未命名的上下文)。或者也许我在这里混淆了太多类别。

我知道,访问说明者的背景是严格基于命名的,并且还有其他方法可以实现这种内部的“发布”,但据我所知,它们要明确得多。通过这种极其隐式的方式在法律上隐式地在外部范围内创建一个未命名的私有内部临时值看起来很可怕,甚至可能非常容易出错,最迟在存在多个参数的情况下(统一初始化的空 std 容器......

C++ 内部类 访问说明符 初始化

评论

1赞 Jarod42 2/15/2021
已在 C++20 IIRC 中修复 ()。private:Accessor() = default;
0赞 Jarod42 2/15/2021
aggregate_initialization规则已更改。(可能是为了解决这样的问题(不容易看到所有可能的交互))。
0赞 Secundi 2/15/2021
@Jarod42谢谢!也许我应该尝试在我的问题中进一步强调非聚合情况,以更多地关注查找行为本身的核心问题。
0赞 t.niese 2/15/2021
这并不能回答这个问题,但如果你需要公开,那你为什么需要公开呢?// This was intended to be the only public construction wayexplicit NeedsFactoryForPublicCreation(Accessor) {}
1赞 Jarod42 2/15/2021
@t.niese:例如std::make_unique

答: 暂无答案