C ++:Boost.MPL等效于在类型向量中调用第i个类型的函数

时间:2014-08-04 07:32:27

标签: c++ templates boost template-meta-programming boost-mpl

我设计了这样的功能:

template<template<class> class TMapper, class TResult = void, class TUserContext>
static typename TResult mapParam(int index, TUserContext ctx)

需要TMapper,它需要符合以下概念:

template<class T> struct Mapper { static TResult map(int index, TUserContent ctx) {} }

Mapper类型为每个参数实例化一次,但“map”函数仅针对给定索引处的参数调用。 Mapper使用参数的类型(T)进行参数化。在测试中,我们希望能够对我们甚至不知道存在的参数执行某些操作,并且仍然使用其精确类型,但不将任何模板元编程添加到实际测试用例中...

有没有办法做到这一点的Boost.MPL,所以有人读这段代码不需要理解它,但可能只是使用提升知识,或者至少有更详细的文档在这里?

这是完整的代码(T :: TParams是任意函数参数类型的boost :: mpl :: vector&lt;&gt;):

template<template<class> class TMapper, class TResult = void, class TUserContext>
        static typename TResult mapParam(int index, TUserContext ctx) {
            return mapParamInternal<TMapper, TResult, boost::mpl::size<T::TParams>::value - 1>(index, ctx);
        }

template<template<class> class TMapper, class TResult, int CurrentIndex, class TUserContext>
static typename boost::enable_if_c<CurrentIndex >= 0, TResult>::type mapParamInternal(int targetIndex, TUserContext ctx) {
    if(CurrentIndex == targetIndex) {
        return TMapper<
            typename boost::mpl::at<
                T::TParams, 
                boost::mpl::int_<CurrentIndex>
            >::type>::map(targetIndex, ctx);
    } else {
        return mapParamInternal<TMapper, TResult, CurrentIndex - 1>(targetIndex, ctx);
    }
}

template<template<class> class TMapper, class TResult, int CurrentIndex, class TUserContext>
static typename boost::disable_if_c<CurrentIndex >= 0, TResult>::type mapParamInternal(int targetIndex, TUserContext ctx) {
    UNREFERENCED_PARAMETER(targetIndex);
    UNREFERENCED_PARAMETER(ctx);
    return TResult();
}

为您举例说明这可能有用:

template<class TParam>
struct UpdateParameter {
    static void map(int index, CallSerializerTest<T>* self) {
        self->trace.updateParameter(
            TCallSig::getParamName(index), 
            TypeUpdatedValue<TParam>::get());
    }
};

void updateParameter(int index) {
    updatedParams.push_back(index);
    TCallSig::mapParam<UpdateParameter>(index, this);
}

对于“index”给出的参数,上面的代码将调用“self-&gt; trace.updateParameter”一次,“TParam”将具有该参数的正确类型。 “TCallSig”是一个任意调用签名,其中定义了“mapParam”函数。我们通过Google测试类型参数化测试获得了大量的签名。我认为这是一个非常酷的系统,它使得测试用例非常简洁,一旦你掌握了元编程背后的内容就很容易阅读。

1 个答案:

答案 0 :(得分:2)

检查Boost.Fusion库。该库旨在充当编译时和运行时世界之间的桥梁,提供使用两个世界属性的功能和算法。
该库具有功能性的非可变精神,并提供类似于函数语言(如map,fold等)的算法。但重点是Fusion能够在此类构造中使用编译时属性(感谢MPL) 。例如(从介绍中提取):

template <typename Sequence>
void xml_print_pointers(Sequence const& seq)
{
    for_each(filter_if<boost::is_pointer<_> >(seq), print_xml());
}

正如您所看到的,只有当该元素是指针(这是元素类型的编译时属性)时,它才会对运行时序列的每个元素执行操作。

我确信你可以使用这些结构轻松实现你的算法。