Подтвердить что ты не робот

Возможно ли итерация mpl:: vector во время выполнения без создания экземпляров в векторе?

Как правило, я использовал бы boost::mpl::for_each<>() для перемещения по 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 был создан вообще до вызова. Любые другие советы/предложения также приветствуются.

4b9b3361

Ответ 1

Интересный вопрос! Насколько я могу судить, 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"
}

Ответ 2

Просто столкнулся с той же ситуацией и дал другое решение проблемы, которую я хотел бы поделиться. Это не так очевидно, но использует существующий алгоритм. Идея состоит в том, чтобы использовать указатели вместо этого.

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());
}

поэтому здесь мы получаем нулевые указатели, но нам все равно, поскольку мы не будем их использовать.

Как я уже говорил, это не очевидно в коде и, вероятно, потребует дополнительных комментариев, но он все еще решает вопрос, не набирая никакого дополнительного кода.

добавлен

Я думаю, что Диего Севилья предложила нечто подобное.

Ответ 3

Ну, во-первых, статический вызов в вашем коде означает, что ваш объект будет существовать. До и после в этом смысле бессмысленно. Единственный раз: "Я не хочу, чтобы T был создан вообще до вызова", имеет смысл, когда T является шаблоном. Это не так, потому что этого не может быть. Верно, что именно эта строка заставляет объект существовать, но я уверен, что он будет существовать не только после компиляции продукта.

Во-вторых, я не считаю, что существует текущий метод для использования for_each без создания экземпляра. IMHO это ошибка в MPL, вызванная сомнительным решением использовать operator(). Не скажу, что это неправильно, так как я знаю разработчика, и он намного умнее, чем я, но теперь кажется, что теперь вы это делаете.

Итак, я думаю, вы застряли, чтобы переделать for_each, который вызывает шаблонную функцию, которая не требует параметра. Я почти уверен, что это возможно, но также в равной степени уверенно, что он не доступен в качестве готового компонента в MPL.

Ответ 4

Марк, ты прав. Я думал об этом, и я не вижу в этом легкого решения. Даже если вы не можете написать пустой operator(), было бы, по крайней мере, возможно использовать указатель, для которого не нужен фактический объект. Кажется, вам нужно выполнить собственную реализацию.

Ответ 5

Вот альтернативное решение, которое было вдохновлено Люком Торайлом.

Эта версия выполняется с помощью Классы метафайлов вместо функций, которые позволяют вызывать static_for_each даже вне областей функций (полезно, если работа должна быть полностью выполнена в compiletime, поэтому у вас нет ненужных функций, называемых во время выполнения).

Кроме того, это дает больше взаимодействия благодаря first и last typedefs, позволяющим получать информацию из цикла, если это необходимо, немного похоже на способ работы return для функции.

Вы также можете получить доступ к предыдущему результату итерации в каждой итерации, благодаря второму параметру шаблона Previous, переданному классу metafunction 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...), поскольку вы можете напрямую взаимодействовать с циклом.

Ответ 6

Мне понравилось (опрошено) решение с указателем и собственной функцией * _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());
}