unordered_map 具有私有构造函数的值类型

unordered_map value type with private constructor

我需要以下代码:

class myclass{
    private:
        myclass(){}

        friend myclass *make_myclass(const std::string&);
};

std::unordered_map<std::string, myclass> myclasses;

myclass *make_myclass(const std::string &str){
    if(myclasses.find(str) == myclasses.end())
        myclasses.emplace(str, myclass{});
    return &myclasses[str];
}

但是编译这段代码会出现一个很长的错误,关于 myclass() 是私有的。

所以我想我会放置 std::pair 并使其成为朋友:

class myclass{
    private:
        myclass(){}

        friend myclass *make_myclass(const std::string&);
        friend class std::pair<std::string, myclass>;
};

std::unordered_map<std::string, myclass> myclasses;

myclass *make_myclass(const std::string &str){
    if(myclasses.find(str) == myclasses.end())
        myclasses.emplace(
            std::piecewise_construct,
            std::forward_as_tuple(str),
            std::forward_as_tuple()
        );
    return &myclasses[str];
}

但是仍然得到关于构造函数是私有的错误。

我怎样才能拥有具有私有构造函数的类型的 std::unordered_map

您的错误将参考这一行:

return &myclasses[str];

这是因为 operator[] 必须默认构造一个值,如果它不存在于特定键的映射中。由于该操作员不是 myclass 的朋友,您会收到访问错误。

相反,您应该利用 emplace returns 它插入的迭代器这一事实:

myclass *make_myclass(const std::string &str) {
    auto it = myclasses.find(str);
    if (it == myclasses.end()) {
        it = myclasses.emplace(str, myclass{}).first;
    }
    return &it->second;
}

这还有一个额外的好处,就是不必在 str 上进行第二次查找。