遍历boost :: mpl :: list的惯用方法是什么?

时间:2009-07-26 20:28:51

标签: c++ boost metaprogramming boost-mpl

编辑:我编辑了示例以更好地解决我的问题,现在函数依赖于常规参数(而不仅仅是模板参数),这意味着计算不能在编译时制作。


我用手写typelist编写了一些代码,现在我们已经开始使用boost而我正在尝试将其移至mpl库。

我似乎无法为mpl::list找到任何体面的文档,我甚至无法将代码移植到boost::mpl。我有这种感觉,即使在(如果?)我成功移植代码时,它仍然不是惯用的。你可以告诉我如何使用boost编写以下内容(请注意,这不是实际的代码,而是一种人为的简化)。

原始代码 (codepad.org paste)

class nil {};

template <class Head, class Tail = nil>
struct type_list {
    typedef Head head;
    typedef Tail tail;
};

template <class List>
struct foo;

template <class Head, class Tail>
struct foo<type_list<Head, Tail> >{
    template <class T>
    static void* bar(T* obj, size_t size)
    {
        if (sizeof(Head) == size) 
            return reinterpret_cast<Head*>(obj);

        // Otherwise check the rest of the list
        return foo<Tail>::bar(obj, size);
    }
};


template <>
struct foo<nil>
{
    template <class T>
    static void* bar(T*, size_t)  { return NULL; }
};

#include <iostream>

int main()
{
    int n = 3;
    void *p = foo<type_list<char, type_list<bool, 
                      type_list<double, type_list<long> > > >
                 >::bar(&n, 4); 
    std::cout<< p << std::endl;
}

失败尝试使用Boost (codepad.org paste)

#include <boost/mpl/list.hpp>

template <class List>
struct foo{
    template <class T>
    static void* bar(T* obj, size_t size)
    {
        typedef typename boost::mpl::front<List>::type type;
        if (sizeof(type) == size) 
            return reinterpret_cast<type*>(obj);

        // Otherwise check the rest of the list
    return foo<typename List::next>::bar(obj, size);
  }
};

template <>
struct foo<boost::mpl::list0<boost::mpl::na> >
{
    template <class T>
    static void* bar(T*)
    {
        return NULL;
    }
};

#include <iostream>

int main()
{
    int n = 3;
    void *p = foo<boost::mpl::list<char, bool, double, long> >::bar(&n, 4);
    std::cout << p << std::endl;
}

4 个答案:

答案 0 :(得分:4)

MPL不适合混合编译时/运行时操作。

MPL序列在运行时允许的唯一操作是'for_each'。对于所有其他情况,你应该自己动手。

因此,您应该有效地考虑MPL类型并不意味着实现。

然而,Boost中还有其他设施可供这样做。

旧:Boost.Tuple

新:Boost.Fusion&gt; http://spirit.sourceforge.net/dl_more/fusion_v2/libs/fusion/doc/html/index.html

Boost.Fusion有点复杂(例如,它集成了视图的概念),但更适合你的例子。

这并不意味着您不应该使用MPL。相反,在Boost.Fusion参考文档中明确指出,应该使用MPL算法进行编译时计算,然后仅在跨越编译时/运行时边界时构建Boost.Fusion容器(甚至虽然Boost.Fusion容器应该与MPL算法一起工作)。

因此,保持您的mpl实现将结果列表转换为Boost.Fusion序列。 然后实例化序列并使用所有Boost.Fusion工具。

答案 1 :(得分:2)

像这样使用boost::mpl::fold

#include <boost/mpl/list.hpp>
#include <boost/mpl/fold.hpp>

#include <iostream>

using namespace boost::mpl;

// Initial state:
struct foo_start {
    template <typename T>
    static void * bar( T *, size_t ) { return 0; }
};

// Folding Step: add This to Prev
template <typename Prev, typename This>
struct foo_iteration {
    struct type {
        template <typename T>
        static void * bar( T * obj, size_t size ) {
            if ( sizeof(This) == size )
                return reinterpret_cast<This*>(obj);
            else
                return Prev::bar( obj, size );
        }
    };
};

// foo is just calling mpl::fold now:
template <typename List>
struct foo : fold< List, foo_start, foo_iteration<_,_> >::type {};

int main() {
    int n = 3;
    void * p = foo< list<char, bool, double, long> >::bar( &n, 4 );
    std::cout << p << std::endl;
}

在这里打印0,但之后我在amd64,所以我需要将4更改为8,并获得非零值。

HTH

答案 2 :(得分:0)

警告:有一段时间没有做过任何C ++(元编程),所以我可能错了。

如果我理解正确,你的原始代码会找到第一个类型,它与传递的参数具有相同的大小,并将参数强制转换为该类型。假设用mpl实现它基本上归结为使用find_if算法和自定义书写谓词来测试类型大小(参见上面链接中的示例)。只需typedef结果,投下它就可以了。

答案 3 :(得分:0)

如果我理解正确,你在运行时传入一个T并希望你的MPL列表{A,B,C,D}将选择并对该集合中的正确T进行操作?

我可能错了,但这听起来像Boost.Fusion,它是为编译时序列的运行时迭代而设计的。