1

编辑:我已经编辑了示例以更好地类似于我遇到的问题,现在该函数取决于常规参数(而不仅仅是模板参数),这意味着无法在编译时进行计算。


我用手写类型列表写了一些代码,现在我们已经开始使用boost,我正试图将它移到mpl库中。

我似乎找不到任何像样的文档,mpl::list甚至无法将代码移植到boost::mpl. 我有一种感觉,即使(如果?)我确实成功地移植了代码,它仍然不会是惯用的。能否请您告诉我应该如何编写以下boost代码(请注意,这不是实际代码,这是人为的简化)。

原始代码 (codepad.org 粘贴)

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 粘贴)

#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

4 回答 4

4

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

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

因此,您应该有效地考虑 MPL 类型并不是要实例化的。

但是,Boost 中还有其他功能可以解决此类问题。

旧:Boost.Tuple

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

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

It does not mean that you should not use the MPL. On the contrary, it is explicitly stated in the Boost.Fusion reference document that one should use MPL algorithms for compile-time computations, and then build the Boost.Fusion container only at the moment you cross the compile-time / runtime boundary (even though Boost.Fusion container are supposed to work with MPL algorithms).

So, keep your mpl implementation transform the resulting list to a Boost.Fusion sequence. Then instantiate the sequence and make use of all the Boost.Fusion facilities.

于 2009-07-29T16:34:11.483 回答
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 上,所以我需要将 更改48,并得到非零的东西。

高温高压

于 2009-07-26T20:49:07.250 回答
0

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

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

于 2009-07-26T20:50:41.727 回答
0

如果我理解正确,您是在运行时传入一个 T 并希望您的 {A, B, C, D} 的 MPL 列表将选择该集合中的正确 T 并对其采取行动?

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

于 2009-07-27T13:30:26.600 回答