如何遍历非默认构造类的提升 MPL 列表

How do I loop over a boost MPL list of non-default constructed classes?

本文关键字:列表 MPL 默认 何遍历 遍历      更新时间:2023-10-16

我有以下示例:

#include <iostream>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/list.hpp>
struct one {};
struct two {};
struct three {};
struct four {};
struct five { five() = delete; };
template <typename T>
void print()
{
  std::cout << "hello " << typeid(T).name() << std::endl;
}
struct type_printer
{
  template <typename T>
  void operator()(T)
  {
    print<T>();
  }
};
int main()
{
  typedef boost::mpl::list<
    one,
    two,
    three,
    four,
    five
  >::type type_list;
  boost::mpl::for_each<type_list>(type_printer());
}

如果我不在列表中包含第五个对象,这绝对可以正常工作,但是一旦我这样做,我就会收到以下错误:

In file included from /usr/local/include/boost_1_56_0/boost/mpl/for_each.hpp:29:0,
                 from mpldef.cpp:3:
/usr/local/include/boost_1_56_0/boost/utility/value_init.hpp: In constructor ‘boost::initialized<T>::wrapper::wrapper() [with T = five]’:
/usr/local/include/boost_1_56_0/boost/utility/value_init.hpp:109:7:   instantiated from ‘boost::initialized<T>::initialized() [with T = five]’
/usr/local/include/boost_1_56_0/boost/utility/value_init.hpp:205:12:   instantiated from ‘boost::value_initialized<T>::value_initialized() [with T = five]’
/usr/local/include/boost_1_56_0/boost/mpl/for_each.hpp:81:9:   recursively instantiated from ‘static void boost::mpl::aux::for_each_impl<false>::execute(Iterator*, LastIterator*, TransformFunc*, F) [with Iterator = boost::mpl::l_iter<boost::mpl::list4<two, three, four, five> >, LastIterator = boost::mpl::l_iter<boost::mpl::l_end>, TransformFunc = boost::mpl::identity<mpl_::na>, F = type_printer]’
/usr/local/include/boost_1_56_0/boost/mpl/for_each.hpp:81:9:   instantiated from ‘static void boost::mpl::aux::for_each_impl<false>::execute(Iterator*, LastIterator*, TransformFunc*, F) [with Iterator = boost::mpl::l_iter<boost::mpl::list5<one, two, three, four, five> >, LastIterator = boost::mpl::l_iter<boost::mpl::l_end>, TransformFunc = boost::mpl::identity<mpl_::na>, F = type_printer]’
/usr/local/include/boost_1_56_0/boost/mpl/for_each.hpp:104:5:   instantiated from ‘void boost::mpl::for_each(F, Sequence*, TransformOp*) [with Sequence = boost::mpl::list5<one, two, three, four, five>, TransformOp = boost::mpl::identity<mpl_::na>, F = type_printer]’
/usr/local/include/boost_1_56_0/boost/mpl/for_each.hpp:118:3:   instantiated from ‘void boost::mpl::for_each(F, Sequence*) [with Sequence = boost::mpl::list5<one, two, three, four, five>, F = type_printer]’
mpldef.cpp:37:48:   instantiated from here
/usr/local/include/boost_1_56_0/boost/utility/value_init.hpp:77:12: error: use of deleted function ‘five::five()’
mpldef.cpp:10:15: error: declared here

有什么办法可以做到这一点吗?我尝试从type_printer呼叫运算符中删除T,因此它看起来像这样:void operator()(),我仍然收到相同的错误。

我通过添加一个类型包装器结构解决了这个问题,就像在 Boost.Hana 中看到的那样。我将其添加到此评论中发现的好主意中,该评论提到使用boost::mpl::transform将此包装器类型自动添加到列表中的每个项目。

下面详细介绍了我的解决方案:

template <typename T>
struct type_
{
  using type = T;
};
template <typename T>
struct add_type_wrapper
{
  using type = type_<T>;
};

使用这两种新类型,我将type_printer函子更改为如下所示:

struct type_printer
{
  template <typename T>
  void operator()(T)
  {
    using type_t = typename T::type;
    print<type_t>();
  }
};

main 中的boost::mpl::for_each调用现在如下所示:

using boost::mpl::_1;
using wrapped_list = boost::mpl::transform<type_list, add_type_wrapper<_1>>::type;
boost::mpl::for_each<wrapped_list>(type_printer());

感谢您的帮助,我认为这是一个非常好和优雅的解决方案。

您还可以向类型列表中的项目添加一个间接寻址级别,如下所示:

template <typename T>
struct type_ref
{
  typedef T type;
}
struct type_printer
{
  template <typename T>
  void operator()(T)
  {
    print<T>();
  }
  template <typename T>
  void operator()(type_ref<T>)
  {
    print<T>();
  }
};
int main()
{
  typedef boost::mpl::list<
    one,
    two,
    three,
    four,
    type_ref<five>
  >::type type_list;
  boost::mpl::for_each<type_list>(type_printer());
}
你可以

自己做一些事情:

namespace detail {
    template <typename Tuple>
    structure my_for_each_t;
    template <typename... Ts>
    structure my_for_each_t<boost::mpl::list<Ts...>>
    {
        template <typename F>
        void operator()(F f) const
        {
             initializer_list<int>{(static_cast<void>(f<Ts>()), 0)...};
        }
    };
}
template <typename Tuple, typename F>
void my_for_each(F f)
{
    detail::my_for_each_t<Tuple>()(f);
}

或者转换列表以添加指向类型的指针,并更改type_printer

struct type_printer
{
  template <typename T>
  void operator()(T*) // pointer added.
  {
    print<T>();
  }
};