18

通常,我会boost::mpl::for_each<>()用来遍历 a boost::mpl::vector,但这需要一个仿函数,其模板函数声明如下:

template<typename T> void operator()(T&){T::staticCall();}

我的问题是我不希望对象 T 被for_each<>. 我根本不需要 T 参数operator()。有没有办法做到这一点,或者替代方法for_each<>不会将 T 类型的对象传递给模板函数?

理想情况下,我希望 operator() 定义如下所示:

template<typename T> void operator()(){T::staticCall();}

当然,我不希望 T 在调用之前被实例化。也欢迎任何其他提示/建议。

4

6 回答 6

14

刚刚遇到同样的情况,并为我想分享的问题提供了不同的解决方案。它并不那么明显,但它使用了现有的算法。这个想法是改用指针。

typedef boost::mpl::vector<type1*, type2*> container;

struct functor
{
    template<typename T> void operator()(T*)
    {
        std::cout << "created " << typeid(T).name() << std::endl;
    }
};

int main()
{
    boost::mpl::for_each<container>(functor());
}

所以在这里我们得到一个空指针,但我们不在乎,因为我们不会使用它们。

正如我之前所说,这在代码中并不明显,可能需要一些额外的注释,但它仍然可以解决问题而无需编写任何额外的代码。

添加

我认为Diego Sevilla提出了类似的建议。

于 2010-11-07T08:30:30.320 回答
13

有趣的问题!据我所知,Boost.MPL 似乎没有提供这样的算法。但是,使用迭代器编写自己的代码应该不会太困难。

这是一个可能的解决方案:

#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/next_prior.hpp>
#include <boost/mpl/vector.hpp>

using namespace boost::mpl;


namespace detail {

template < typename Begin, typename End, typename F >
struct static_for_each
{
    static void call( )
    {
        typedef typename Begin::type currentType;

        F::template call< currentType >();
        static_for_each< typename next< Begin >::type, End, F >::call();
    }
};


template < typename End, typename F >
struct static_for_each< End, End, F >
{
    static void call( )
    {
    }
};

} // namespace detail


template < typename Sequence, typename F >
void static_for_each( )
{
    typedef typename begin< Sequence >::type begin;
    typedef typename end< Sequence >::type   end;

    detail::static_for_each< begin, end, F >::call();
}

【命名可能选得不太好,但是好……】

以下是使用此算法的方法:

struct Foo
{
    static void staticMemberFunction( )
    {
        std::cout << "Foo";
    }
};


struct Bar
{
    static void staticMemberFunction( )
    {
        std::cout << "Bar";
    }
};


struct CallStaticMemberFunction
{
    template < typename T >
    static void call()
    {
        T::staticMemberFunction();
    }
};


int main()
{
    typedef vector< Foo, Bar > sequence;

    static_for_each< sequence, CallStaticMemberFunction >(); // prints "FooBar"
}
于 2010-10-29T16:29:33.497 回答
1

好吧,首先,代码中的静态调用意味着您的对象将存在。在这方面,之前/之后是没有意义的。唯一一次,“我不希望 T 在调用之前被实例化”是有意义的,当 T 是一个模板时。不是,因为不可能。确实是那条线导致对象存在,但我很确定一旦产品被编译,它就不会只存在于那里。

其次,我不相信当前有一种无需实例化即可使用 for_each 的方法。恕我直言,这是 MPL 中的一个错误,由使用 operator() 的可疑决定引起。不会说这是错误的,因为我认识开发人员,而且他比我聪明得多,但是现在你提出这个问题似乎是这样。

所以,我认为你不得不重新制作一个调用不需要参数的模板化函数的 for_each 。我几乎可以肯定它是可能的,但也同样可以肯定,它在 MPL 中作为预制组件并不容易获得。

于 2010-10-29T16:27:56.580 回答
1

马尔辛,你说的很对。我一直在考虑这个问题,但我没有看到一个简单的解决方案。即使你不能写 empty operator(),至少可以使用一个不需要实际对象存在的指针。看来,您必须推出自己的实现。

于 2010-10-29T16:40:25.173 回答
1

这是一个从Luc Touraille 的回答中受到高度启发的替代解决方案。

这个版本是使用Metafunction 类而不是函数来完成的,它允许在static_for_each函数范围之外调用 (如果工作必须在编译时完全完成,所以在运行时没有调用不必要的函数时很有用)。

此外,由于firstlasttypedef,它提供了更多的交互,允许在必要时从循环中获取信息,有点像 areturn为函数工作的方式。

Previous由于传递给元函数类的第二个模板参数,您还可以在每次迭代中访问上一次迭代结果F

最后,您可以使用模板参数向循环过程提供数据Initial,它将作为Previous第一次迭代的参数值给出。

# include <boost/mpl/begin_end.hpp>
# include <boost/mpl/next_prior.hpp>
# include <boost/mpl/apply.hpp>

namespace detail_static_for_each
{
  // Loop
  template<typename Begin, typename End, typename F, typename Previous>
  struct static_for_each
  {
  private:
    typedef typename Begin::type                                current_type;

  public:
    typedef typename boost::mpl::apply<F, current_type, Previous>::type             first;
    typedef typename static_for_each<typename boost::mpl::next<Begin>::type, End, F, first>::last   last;
  };

  // End of loop
  template<typename End, typename F, typename Last>
  struct static_for_each<End, End, F, Last>
  {
  public:
    typedef Last    first;
    typedef Last    last;
  };

} // namespace detail_static_for_each

// Public interface
template<typename Sequence, typename F, typename Initial = void>
struct  static_for_each
{
private:
  typedef typename boost::mpl::begin<Sequence>::type        begin;
  typedef typename boost::mpl::end<Sequence>::type          end;

  typedef typename detail_static_for_each::static_for_each<begin, end, F, Initial>  loop;

public:
  typedef typename  loop::first                 first;
  typedef typename  loop::last                  last;
};

这是一个提供和检索数据的简单示例:

# include <iostream>

# include <boost/type_traits/is_same.hpp>

# include <boost/mpl/if.hpp>
# include <boost/mpl/vector.hpp>

# include "static_for_each.hpp"

struct is_there_a_float                                                                                                                                                                                              
{                                                                                                                                                                                                                    
    template<typename currentItem, typename PreviousIterationType>                                                                                                                                                     
    struct apply                                                                                                                                                                                                       
    {                                                                                                                                                                                                                  
        typedef typename boost::mpl::if_< PreviousIterationType,                                                                                                                                                         
                                          PreviousIterationType,                                                                                                                                                         
                                          boost::is_same<float, currentItem> >::type    type;                                                                                                                        
    };                                                                                                                                                                                                                 
};

struct  test                                                                                                                                                                                                         
{                                                                                                                                                                                                                    
    typedef boost::mpl::vector< char, long, long, double, float, int, char > sequence;                                                                                                                                 

    typedef static_for_each<sequence, is_there_a_float, boost::false_type>::last    found;                                                                                                               
};

int     main(void)                                                                                                                                                                                                   
{                                                                                                                                                                                                                    
    std::cout << std::boolalpha << test::found::value << std::endl;                                                                                                                                                    

    return (0);                                                                                                                                                                                                        
}

这些特性使得使用static_for_each更类似于使用常见的运行时循环(while, for, BOOST_FOREACH ...),因为您可以更直接地与循环交互。

于 2012-10-30T19:24:33.077 回答
0

我喜欢(赞成)带有指针和自己定义的 *_for_each 函数的解决方案。如果目标是在需要之前避免创建对象,这是使用 T 类型包装器的替代方法。

template<typename T>
struct Wrapper
{
  typedef T type;
};

struct Functor
{
  template<typename T> void operator()(T t)
  {
    T::type obj(1);
    T::type::static_fuc();
  }
};

struct T1
{
  T1(int a) : m_a(a) { }
  int m_a;
  static inline void static_fuc() { }
};
struct T2
{
  T2(int a) : m_a(a) { }
  int m_a;
  static inline void static_fuc() { }
};

void fun()
{
  namespace mpl=boost::mpl;
  typedef mpl::vector<Wrapper<T1>,Wrapper<T2> > t_vec;
  mpl::for_each<t_vec>(Functor());
}
于 2017-06-07T12:53:08.610 回答