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

C++ define a class member type according to its template

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

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;
}

class A是元编程的,可以是string、int等。 我想更改代码,以防万一 class A 是 "meta string" 将使用地图,否则将使用 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;
}

对于使用不同地图类型的任何其他建议也将不胜感激。

谢谢

一个简单的解决方案是使用 std::conditional 检查 A 是否与您的 "meta string" class 相同(我选择 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;
};

使用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 替换为 using 类型别名,您也应该这样做。

剩下的就是实现 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

假设 "meta string" 的类型为 foo(我刚编的一个虚构名称,因为你没有指定 "meta string" 是什么,你可以简单地做

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;
};

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

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;
};

(对于 C++11 之前的版本,我会使用 boost::unordered_map 而不是 std::unordered_map