我正在尝试找到一种优雅的方式来实现类似于非常简单的boost::mpl
类型的地图
在我的上下文中,不能使用MPL或任何其他boost
库。此外,我真正需要的唯一操作是初始化和查找。存储编译时值也很好(如果我使用基于boost::fusion::set
的解决方案,我可以使用boost
执行此操作。)
我知道如何用traits类做我想做的事情,但我认为语法有点过于冗长并且有一些其他的小缺点,例如:你不能在类声明中定义特征特化,而且,通常情况下,它并不是整齐地放在一个地方。
这是我想要使用特征实现的目标:
// base class definitions
class Foo {};
class Bar {};
class Baz {};
// traits base
template<typename T>
struct MyTraits {};
// traits specializations
template<>
struct MyTraits<Foo> {
static constexpr const char* name = "foo";
typedef double type;
};
template<>
struct MyTraits<Bar> {
static constexpr const char* name = "bar";
typedef std::string type;
};
// generic worker function
template<typename T>
void doStuff(const T& arg) {
std::cout << "got a " << MyTraits<T>::name << " - size: " << sizeof(typename MyTraits<T>::type) << std::endl;
}
int main(int, char*[]) {
Foo foo;
Bar bar;
Baz baz;
doStuff(foo);
doStuff(bar);
// this fails, as expected:
//doStuff(baz);
}
以下是我希望能够使用的语法:
typedef TMapTemplate<
TMapEntry<Foo, double, "foo">,
TMapEntry<Bar, string, "bar">
> tTraitsMap;
// generic worker function
template<typename T>
void doStuff(const T& arg) {
std::cout << "got a " << at<tTraitsMap,T>::value<1>() << " - size: " << sizeof(at<tTraitsMap,T>::type<0>) << std::endl;
}
(像这样的东西会是理想的,但我会很满意一个简单的一对一类型地图,真的)
答案 0 :(得分:0)
所以,我最后修补了一些或多或少的东西。它无论如何都不是完美的,但确实符合我想要的简单版本:
模板:
struct NotFound {};
template <typename TK, typename TV>
struct TMapEntry {
};
template <typename... TEntries>
struct TMap {
};
template <typename TK, typename TV, typename... TEntries>
struct TMap<TMapEntry<TK, TV>, TEntries...> {
typedef TMap<TEntries...> tNext;
template<typename T>
struct HeadResolver {
static constexpr bool match = is_same<TK, T>::value;
};
template<typename T>
using at = typename conditional<HeadResolver<T>::match, TV, typename tNext::template at<T>>::type;
};
template<>
struct TMap<> {
template<typename T>
using at = NotFound;
};
用法:
class Foo {};
class Bar {};
class Baz {};
void test() {
typedef TMap<> tEmptyMap;
static_assert(is_same<tEmptyMap::at<Foo>, NotFound>::value, "found something in empty map");
static_assert(is_same<tEmptyMap::at<int>, NotFound>::value, "found something in empty map");
typedef TMap<
TMapEntry<Foo, int>,
TMapEntry<Bar, float>,
TMapEntry<void, string>
> tMap;
static_assert(is_same<tMap::at<Foo>, int>::value, "map mismatch");
static_assert(is_same<tMap::at<Bar>, float>::value, "map mismatch");
static_assert(is_same<tMap::at<void>, string>::value, "map mismatch");
static_assert(is_same<tMap::at<Baz>, NotFound>::value, "map mismatch");
}
我在做这个时想到了几点:
typedef TMap<Foo, int, Bar, float, void, string> tMap;
,看起来更灵活,但可能会隐藏错误。