初始化静态std :: map <int,unique_ptr <int =“”>&gt;在C ++中</int,>

时间:2015-03-06 15:19:26

标签: c++ templates inheritance static-initialization

这是post的一个类似问题。我认为最有希望的答案与模板化静态初始化有关。这是答案中的课程:

template <typename T, typename U>
class create_map
{
private:
    std::map<T, U> m_map;
public:
    create_map(const T& key, const U& val)
    {
        m_map[key] = val;
    }

    create_map<T, U>& operator()(const T& key, const U& val)
    {
        m_map[key] = val;
        return *this;
    }

    operator std::map<T, U>()
    {
        return m_map;
    }
};

用法:

std::map mymap = create_map<int, int >(1,2)(3,4)(5,6);

这适用于结构或类以及基类型。我想要做的是使用unique_prt<Structure\Class>作为这样的值:

std::map mymap = create_map<DWORD, std::unique_ptr<Structure|Class>>(1, new Structure|Class())(2, new Structure|Class())

我正在尝试使用模板类,以便我可以将值设置为任何类型。我从这个post得到了一个想法,即使用接口作为基类,然后使用模板派生类来保存任何类型的值。所以那些类看起来像这样:

class MyFieldInterface
{
public:
    int m_Size;
    virtual ~MyFieldInterface() = default;
}

template <typename T>
class MyField : public MyFieldInterface {
    T m_Value; 
}

然后可以像我之前描述的那样设置地图:

std::map<DWORD, unique_ptr<MyFieldInterface>> mymap;

但尝试使用create_map初始化它失败了:

std::map mymap = create_map<DWORD, unique_ptr<MyFieldInterface>>(1, new MyField<DWORD>())(2, new MyField<char>())(3, new MyField<WORD>())

我得到的错误是:

operator()
Error: no instance of constructor "create_map<T, U>::create_map [with T=DWORD, U=std::unique_ptr<MyFieldInterface, std::default_delete<MyFieldInterface>>]" matches the argument list
argument types are: (DWORD, MyField<DWORD>*)

所以我认为我需要一个能够正确处理指针的构造函数和operator()。我在课堂上加了两个:

create_map(const T& key, const U* val)
{
    m_map[key] = val;
}

create_map<T, U>& operator()(const T& key, const U* val)
{
    m_map[key] = val;
    return *this;
}

我得到了同样的错误。所以我尝试了没有*

create_map(const T& key, const U val)
{
    m_map[key] = val;
}

create_map<T, U>& operator()(const T& key, const U val)
{
    m_map[key] = val;
    return *this;
}

我得到了同样的错误。在我写这篇文章时,我意识到问题可能与继承有关,而不一定是create_map的运算符。 你能帮我弄清楚我需要的operator()定义或基本/派生类定义吗?

请将您的答案限制为不包括Boost C ++库,因为我不允许在工作中使用它们。

编辑:根据T.C。

的要求更新了MyFieldInterface

2 个答案:

答案 0 :(得分:2)

这是一种可能的实施方式:

template <typename T, typename U>
class create_map
{
private:
    std::map<T, U> m_map;
public:
    create_map(T key, U val)
    {
        m_map.emplace(std::move(key), std::move(val));
    }

    create_map&& operator()(T key, U val) &&
    {
        m_map.emplace(std::move(key), std::move(val));
        return std::move(*this);
    }

    operator std::map<T, U>() &&
    {
        return std::move(m_map);
    }
};

注意按值获取参数,然后使用emplace将其移动到地图中,并从m_map移动转换运算符。

我不知道MSVC 2012是否支持ref-qualifiers。如果没有,则需要将其删除(在功能参数列表后面的两个&&)。关键是要强制create_map只能用作临时用途。也可以强制转换操作符只被调用一次,但我在上面的代码中没有这样做。

现在你的调用不能使用裸new因为1)它不是异常安全的,2)原始指针不能隐式转换为unique_ptr s。一个简单的make_unique实现不考虑数组

namespace util {
    template<class T, class... Args>
    std::unique_ptr<T> make_unique(Args&&... args) {
        return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
}

然后,您可以将new MyField<DWORD>()更改为util::make_unique<MyField<DWORD>>() *

Demo


* 使用限定调用会禁用ADL,如果您的调用有参数,则can have surprising effects when you upgrade your compiler。根据规范的make_unique的完整实施可以在N3656make_unique提案文件中的示例代码中找到。

答案 1 :(得分:0)

在T.C.的一些指导下而VC2012中没有make_unique的事实,我改变了使用unique_ptr&lt;&gt;到shared_ptr&lt;&gt;。

std::map mymap = create_map<DWORD, shared_ptr<MyFieldInterface>>(1, make_shared<MyField<DWORD>>())(2, make_shared<MyField<char>>())(3, make_shared<MyField<WORD>>())

这给了我正在寻找的功能,而无需更改底层类。虽然这可以满足我的需要,但实际上我将T.C.的答案标记为正确,因为无论你使用哪一个,它都能正常工作。