如何隐式调用 shared_ptr 中包装的值的构造函数,该值位于 std::map 集合中

How to call implicitly constructor of value wrapped in shared_ptr which is placed in std::map collection

我正在使用代码生成器,我无法直接获取包装在 shared_ptr 中并放置在 std::map.

中的值的类名

我遇到了这样一种情况,我需要创建新的地图对象,但无法访问类名,我无法执行有效的对象构造函数调用。我尝试使用映射运算符 at[],它调用值构造函数,但它调用 shared_ptr<T> 构造函数并且内部对象保持未初始化状态。

这里是例子:

#include <iostream>
#include <map>
#include <memory>

class A
{
public:
    A() { std::cout << "A"; }
    int getMember() const { return m_member; }
private:
    int m_member = 1;
};

int main()
{
    std::map<int, A> mapIntToA;
    std::map<int, std::shared_ptr<A>> mapIntToAptr;

    mapIntToA[1]; // runs A constructor
    std::cout << mapIntToA[1].getMember();
    
    mapIntToAptr[1]; // runs shared_ptr constructor
    // cant call methods of uninitalized object
    // std::cout << mapIntToAptr[1]->getMember();
    
    // this init works, but I can't use classname 'A' in my code generator
    // mapIntToAptr[1] = std::make_shared<A>();
    
    return 0;
}

您可以使用 std::mapstd::shared_ptr 的成员类型来获取元素的类型。

类似

using type = typename std::map<int, std::shared_ptr<A>>::mapped_type::element_type;
mapIntToAptr[1] = std::make_shared<type>();
mapIntToAptr.emplace(1, ::std::make_shared<decltype(mapIntToAptr)::mapped_type::element_type>());

请注意,使用 emplace 可以防止在 make_shared 抛出时 map 留下 nullptr 值的情况。

operator[] of std::map 默认构造缺少值。

因此,您可以将 std::shared_ptr 包装到一个 class 中,它会按预期构造您的内部 class,例如:

template <typename T>
struct shared_ptr_wrapper
{
    std::shared_ptr<T> data = std::make_shared<T>();

    operator const std::shared_ptr<T>& () const {return data;}
    operator std::shared_ptr<T>& () {return data;}

    const std::shared_ptr<T>& operator ->() const { return data; }
    std::shared_ptr<T>& operator ->() {return data;}

    const T& operator *() const { return *data; }
    T& operator *() {return *data;}
};

然后

std::map<int, shared_ptr_wrapper<A>> mapIntToAptr;

mapIntToAptr[1]; // runs shared_ptr constructor
std::cout << mapIntToAptr[1]->getMember(); // Ok