braked初始化允许创建临时的*private*结构



我刚刚阅读了Raymond Chen的优秀文章《新旧事物》中的以下文章:https://devblogs.microsoft.com/oldnewthing/20210719-00/?p=105454

我对此有一个问题,最好在下面的代码片段中进行描述。为什么允许初始化"x3"?我看不出下面"x2"one_answers"x3"的初始化之间有任何语义差异。

#include <memory>
class X
{
    struct PrivateTag {};   // default constructor is *NOT* explicit
public:
    X(PrivateTag) {}
    static auto Create() -> std::unique_ptr<X> 
    {
        return std::make_unique<X>(PrivateTag{});
    }
};
int main()
{
    auto x1 = X::Create();          // ok:    proper way to create this
  //auto x2 = X(X::PrivateTag{});   // error: cannot access private struct
    auto x3 = X({});                // ok:    why ?!
}

辅助功能仅限制哪些名称可以显式写出。它决不会阻止使用某个类型。

例如,在返回私有类型的函数上使用decltype,然后给它一个新名称并通过该名称完全访问它,或者使用模板参数推导给不可访问的类型新的别名,通过这些别名可以访问它们。

你能做的最好的事情就是通过使用链接博客文章中讨论的方法,让用户很难意外地滥用构造函数,但如果用户足够坚定,他们几乎总是可以获得PrivateTag的完全可访问的别名,并无论如何使用构造函数。

auto x3 = X({}); 并没有拼出成员类名,所以它的可访问性并不重要。

auto x2 = X(X::PrivateTag{});确实拼写了成员类的名称,因此需要考虑可访问性,这使得它的格式不正确,因为PrivateTag是私有的,在命名它的上下文中是不可访问的。


这里有一个绕过私人标签技巧的例子,无论是否进行了博客文章中建议的调整:

struct any_convert {
    template<typename T>
    operator T() const {
        // Here `T` becomes an alias for `PrivateTag`
        // but is completely accessible.
        return T{};
    }
};
//...
auto x4 = X(any_convert{});

最新更新