填充结构类型已模板化的结构成员

时间:2018-08-03 11:57:35

标签: c++ templates

我有一个函数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

应该使用哪种附加映射来标识正确的模板参数AB

我该如何写fill()来确定要填充的值?

2 个答案:

答案 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>?");

                       ^~~~~~~~~~~~~~~