Is it possible to have a “named constructor” return a privately-constructed, non-moveable, non-copyable std::optional?

后端 未结 1 1462
别那么骄傲
别那么骄傲 2021-01-21 23:32

I mostly work on system-level C++ projects that don\'t allow exceptions to be thrown, but RAII is (rightfully) strongly encouraged. Right now, we handle the lack of failing cons

相关标签:
1条回答
  • 2021-01-21 23:52

    If you want to make any indirect object construction work (emplace in its various forms, in_place constructors of optional, make_shared, etc) , the constructor in question must be public. You can make a constructor public without allowing all public use by using something called a private key.

    Basically, you create a type (call it Key) whose default constructor is private. The class has no members, nor does it do anything. It declares that MyType is a friend of Key; this means that only members of MyType can construct one.

    Now, make all of MyType's constructors public, but they all take a Key const& as the first parameter. This means that in theory anyone could call them, but in practice only someone who has a Key instance can actually call them. Members of MyType can create such an instance, and they can pass those instances to optional's in_place constructor or any other indirect mechanism. This effectively gives the indirect construction mechanism private access to the constructor.

    This is a standard idiom for dealing with forwarding of private access to a type. Indeed, one could hypothetically write a generic key<T> type like this:

    template<typename T>
    class key
    {
    private:
      key() = default;
      key(int) {} //Not an aggregate
    
      friend T;
    };
    

    One small note. Because of an annoyance of C++11 pre-C++20, any type with no members and no constructors other than defaulted/deleted copy/move/default constructors is considered an aggregate. This is true even if you explicitly = default its default constructor. As such, that type can undergo aggregate initialization, which has no public/private distinction. That is, anybody could call your private-key constructors by doing this: MyType({}, <params>);.

    To avoid this, you will need to give Key an additional (private) constructor or otherwise prevent it from being an aggregate.

    0 讨论(0)
提交回复
热议问题