我有一个函数getmp()
,它填充了一些键值对并返回。
map<string, string> getmp()
{
map<string, string> mp;
//fill mp
return mp;
}
键值对将是以下结构之一的变量值(将是更多的值)。将有一个id
成员将标识这些值所对应的结构。
struct A
{
int a;
string b;
};
struct B
{
string c;
};
现在,我想使用此map
填充正确的结构。
template<typename T>
T* fill(map<string, string> mp)
{
T *obj = new T();
//if T is A
obj->a = stoi(mp["a"]);
obj->b = mp["b"];
//else if T is B
obj->c = mp["c"];
return obj;
}
并且将从
调用int main()
{
map<string, string> mp = getmp();
// fill mp for A if mp["id"] = 1
A *a = fill<A>(mp);
//else fill mp for B if mp["id"] 2
B *b = fill<B>(mp);
return 0;
}
我可以维护一个单独的映射,以用id
标识1
A
和用id
标识2
B
。
A
和B
?
我该如何写fill()
来确定要填充的值?
答案 0 :(得分:1)
对于C ++ 17,您可以使用if constexpr
:
template<typename T>
std::unique_ptr<T> fill(map<string, string> mp)
{
auto obj = std::make_unique<T>();
if constexpr (std::is_same<A, T>::value) {
obj->a = stoi(mp["a"]);
obj->b = mp["b"];
else if constexpr (std::is_same<B, T>::value) {
obj->c = mp["c"];
}
return obj;
}
之前,您可以使用专业化:
template<typename T>
std::unique_ptr<T> fill(map<string, string> mp)
{
return std::make_unique<T>();
}
template <>
std::unique_ptr<A> fill(map<string, string> mp)
{
auto obj = std::make_unique<A>();
obj->a = stoi(mp["a"]);
obj->b = mp["b"];
return obj;
}
template <>
std::unique_ptr<B> fill(map<string, string> mp)
{
auto obj = std::make_unique<A>();
obj->c = mp["c"];
return obj;
}
答案 1 :(得分:0)
您可以在C ++ 17之前使用模板专门化来做到这一点:
#include <string>
#include <map>
struct A
{
int a;
int b;
};
struct B
{
std::string a;
int b;
};
struct C
{
std::string c;
};
using property_map = std::map<std::string, std::string>;
// template declaration. We purposley do not include a definition of the general function.
template<typename T>
T* fill(property_map const& pm);
//specialization for struct A
template<>
A* fill<A>(property_map const& pm)
{
// ...
return new A;
}
//specialization for struct B
template<>
B* fill<B>(property_map const& pm)
{
// ...
return new B;
}
void do_the_needful(property_map const& pm)
{
auto a = fill<A>(pm);
auto b = fill<B>(pm);
// auto c = fill<C>(pm); // -> will fail to link since no specialization for C was defined.
}
如果您希望编译器在编译时因忘记特殊化而失败,并显示更多描述性错误消息,则可以在一般情况的定义中使用static_assert,如下所示:
// a template-dependent type that will always be false
template<typename T>
using always_false = std::false_type;
// template general case -- we cause a compiler error to let the user know that they forgot to define the specialization.
template<typename T>
T* fill(property_map const& pm)
{
static_assert(always_false<T>::value, "Don't know how to unpack the property map into this struct type. Did you forget to add a specialization of fill<T>?");
}
这将导致尝试使用非专业的fill<C>
失败,并显示类似以下内容:
<source>: In instantiation of 'T* fill(const property_map&) [with T = C; property_map = std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >]':
<source>:55:28: required from here
<source>:31:23: error: static assertion failed: Don't know how to unpack the property map into this struct type. Did you forget to add a specialization of fill<T>?
static_assert(always_false<T>::value, "Don't know how to unpack the property map into this struct type. Did you forget to add a specialization of fill<T>?");
^~~~~~~~~~~~~~~