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

发布于 2024-07-29 20:36:40 字数 2520 浏览 10 评论 0原文

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


我用手写了一些代码 typelist 现在我们开始使用 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失败< /strong> (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;
}

Edit: I've edited the sample to better resemble the problem I have, now the function depends on a regular parameter (and not only on template parameters) which means that the computations can't be made at compile time.


I wrote some code with a hand written typelist and now we've started using boost and I'm trying to move it to the mpl library.

I can't seem to find any decent documentation for mpl::list and I'm even failing to port the code to boost::mpl. I've got the feeling that even when (if?) I do succeed in porting the code it will still not be idiomatic. Can' you please let me know how the following should be written with boost (note that this is not the actual code, it's a contrived simplification).

Original code (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;
}

Failed Attempt to use 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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

青丝拂面 2024-08-05 20:36:42

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

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

Warning: haven't done any C++ (meta programming for that matter) in a while, so I might be wrong.

If I understand correctly, your original code finds the first type, which has the same size as does the passed argument and casts the argument to that type. Assuming that, implementing it with mpl would basically boil down to using the find_if algorithm with a custom written predicate to test for type size (see the example in the link above). Just typedef the result, cast it and you're done.

ˉ厌 2024-08-05 20:36:42

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

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

If I understand correctly, you're passing in a T at runtime and hoping that your MPL list of {A, B, C, D} will select and act upon the correct T in that set?

I may be wrong, but this sounds like something suited to Boost.Fusion, which is designed for runtime iteration of compile-time sequences.

紫﹏色ふ单纯 2024-08-05 20:36:41

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 有点复杂(例如,它集成了视图的概念),但更适合您的示例。

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

因此,请保持 mpl 实现将结果列表转换为 Boost.Fusion 序列。
然后实例化该序列并使用所有 Boost.Fusion 设施。

The MPL is ill-suited for mixed compile-time / run-time operations.

The only operation allowed at runtime on MPL sequences is 'for_each'. For all other situations you should roll your own.

So you should effectively consider that MPL types are not meant to be instanciated.

However, there are other facilities in Boost for such a thing.

The old: Boost.Tuple

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

Boost.Fusion is a bit more complex (it integrates the concept of views, for example), but would be far better suited to your example.

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.

短叹 2024-08-05 20:36:41

使用 boost::mpl::像这样折叠

#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,并得到非零值。

华泰

Use boost::mpl::fold like this:

#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;
}

Prints 0 here, but then I'm on amd64, so I need to change the 4 to an 8, and get something non-zero.

HTH

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文