C ++根据其模板定义类成员类型

时间:2016-11-01 08:49:22

标签: c++ metaprogramming template-meta-programming

在我们的代码中,我们有以下类:

template<class A, class B>
class myClass
{
    typedef std::list<Object<A,B>> MyList;
    typedef std::map<A, typename mList::iterator> MyMap

    MyList mList;
    MyMap mMap;
}

A类是元编程的,它可以是字符串,int等。 我想更改代码,以便在类A是“元字符串”的情况下使用地图,否则将使用unordered_map。

我尝试添加更多元编程但尚未成功:

template< class A, class B>
struct MapType // default
{
    typedef std::list<Object<A,B>> MyList;
    typedef std::unordered_map<A,B> MyMap;
}

//TODO struct with templated A (string) to use std::map

template<class A, class B>
class myClass
{
    ???? // if A ~ String define myMap to MAP . otherwise unordered

    MyList mList;
    MyMap mMap;
}

使用不同地图类型的任何其他建议也将受到赞赏。

由于

4 个答案:

答案 0 :(得分:3)

一个简单的解决方案是使用std::conditional检查A是否与您的“元字符串”类相同(我选择std::string进行演示):

template<class A, class B>
class myClass
{
    std::list<Object<A,B>> mList;
    std::conditional_t<std::is_same<A,std::string>::value,
                       std::map<A,B>, std::unordered_map<A,B>> mMap;
};

另一种可能性是使用部分专业化:

template<class A, class B>
class myClass
{
    std::list<Object<A,B>> mList;
    std::unordered_map<A,B> mMap;
};

template<class B>
class myClass<std::string,B>
{
    std::list<Object<std::string,B>> mList;
    std::map<std::string,B> mMap;
};

答案 1 :(得分:2)

使用std::conditonal特质:

template<class A, class B>
class myClass
{
    using MyList = std::list<Object<A,B>>;
    using MyMap = std::conditional_t<IsMetaString<A>::value,
                        std::map<A, typename mList::iterator>,
                        std::unordered_map<A, typename mList::iterator>>;

    MyList mList;
    MyMap mMap;
}

请注意我冒昧地使用使用类型别名替换你的tyedef,你也应该这样做。

剩下的就是实现IsMetaString,这取决于你对Meta String的定义可以简单如下:

template <class T> struct IsMetaString : std::false_type {};
template <> struct IsMetaString<std::string> : std::true_type {};

例如,如果使用元字符串,则表示std::string。或者您可以根据需要对其进行修改。

我认为你的意思是typename MyList::iterator而不是typename mList::iterator

答案 2 :(得分:0)

假设“元字符串”的类型为foo(我刚刚编造的虚构名称,因为您尚未指定“元字符串”是什么,您只需执行

template< class A, class B>
struct MapType // default
{
    typedef std::list<Object<A,B>> MyList;
    typedef std::unordered_map<A,B> MyMap;

    MyList mList;
    MyMap mMap;
};


template<class B>
struct MapType<foo, B>
{
     typedef std::list<Object<foo, B>> MyList;
     typedef std::map<foo,B> MyMap;

     MyList mList;
     MyMap mMap;
};

答案 3 :(得分:0)

使用部分特化(用于pre-C ++ 11,可能没有std :: conditional),你不需要专门化整个类(这可能是复制很多方法的一大负担) ,但你可以只专注地图类型:

template<class A, class B>
class myClass
{
    template<class X, class ITER_T>
    struct map_type {
        typedef std::map<X, ITER_T> type;
    };

    template<class ITER_T>
    struct map_type<std::string, ITER_T> {
        typedef boost::unordered_map<A /* or std::string */, ITER_T> type;
    };

    typedef std::list<Object<A,B>> MyList;
    typedef map_type<A, typename MyList::iterator>::type MyMap;

    MyList mList;
    MyMap mMap;
};

(对于pre-C ++ 11,我使用boost::unordered_map代替std::unordered_map