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
)
在我们的代码中,我们有以下 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
)