这是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答案 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>>()
* 。
* 使用限定调用会禁用ADL,如果您的调用有参数,则can have surprising effects when you upgrade your compiler。根据规范的make_unique
的完整实施可以在N3656的make_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.的答案标记为正确,因为无论你使用哪一个,它都能正常工作。