This is a similiar question to this post. The answer that I think has the most promise has to do with templated static initialization. Here is the class from that answer:
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;
}
};
Usage:
std::map mymap = create_map<int, int >(1,2)(3,4)(5,6);
This works great for a structure or a class as well as the base types. What I would like to do is to use this with a unique_prt<Structure\Class>
as the value like this:
std::map mymap = create_map<DWORD, std::unique_ptr<Structure|Class>>(1, new Structure|Class())(2, new Structure|Class())
I am trying to use a template class so that I can have the value be any type. I got the idea from this post to use an interface as a base class and then a template derived class to hold any type of value. So those classes look like this:
class MyFieldInterface
{
public:
int m_Size;
virtual ~MyFieldInterface() = default;
}
template <typename T>
class MyField : public MyFieldInterface {
T m_Value;
}
Then the map can be setup like I described earlier:
std::map<DWORD, unique_ptr<MyFieldInterface>> mymap;
But trying to initialize it with create_map fails:
std::map mymap = create_map<DWORD, unique_ptr<MyFieldInterface>>(1, new MyField<DWORD>())(2, new MyField<char>())(3, new MyField<WORD>())
The error that I get is this:
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>*)
So I thought that I need a constructor and an operator() that can handle the pointer properly. I added both to the class:
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;
}
I got the same error. So I tried without the *
:
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;
}
I got the same error. As I'm writing this, I realized that the problem may be related to the inheritance and not necessarily create_map's operator. Can you help me figure out the operator() definition or the base/derived class definition that I need to get this to work?
Please limit your answers to not include the Boost C++ libraries as I am not allowed to use them here at work.
Edit: updated MyFieldInterface as requested by T.C.
This is one possible implementation:
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);
}
};
Note the taking argument by value and then moving it into the map with emplace
, and the conversion operator that moves from m_map
.
I don't know if MSVC 2012 supports ref-qualifiers. If it doesn't, you'll need to remove it (that's the two &&
s after the function parameter list). The point of that is to enforce that create_map
should only be used as a temporary. It is possible to also enforce that the conversion operator is only called once, but I didn't do that in the code above.
Now your calls cannot use naked new
s because 1) it isn't exception-safe and 2) raw pointers cannot be implicitly converted to unique_ptr
s. A simple make_unique
implementation that doesn't take arrays into account is
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)...));
}
}
You can then change the new MyField<DWORD>()
s to util::make_unique<MyField<DWORD>>()
*.
Demo.
* Using a qualified call disables ADL, which can have surprising effects when you upgrade your compiler if your call has arguments. A full implementation of make_unique
according to the spec can be found in the example code in N3656, the make_unique
proposal paper.