применить boost :: fusion :: for_each для boost :: fusion :: vector с изменяемым функциональным объектом

Я пытаюсь использовать boost :: fusion :: vector. Однако у меня проблемы с очень простой проблемой.

#include <iostream>
#include <string>

#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/algorithm.hpp>

using namespace std;

struct A{
    template <class T>
    void operator()(const T& t) {
        x++;
        cout << t << endl;
    }

    int x = 0;
};

int main(){
    A a;
    boost::fusion::vector<int, int, int> tuple{3,4,5};
    boost::fusion::for_each(tuple, a);
}

Обратите внимание, что operator() из struct A изменяет x в struct A. gcc 4.7.2 предупреждает, что ... \ include \ boost \ fusion \ algorithm \ iteration \ detail \ for_each.hpp: 77: error: передача 'const A' в качестве аргумента 'this' для void A :: operator () ( const T &) [with T = int] 'отбрасывает квалификаторы [-fpermissive]

Есть ли решение для этого?


person Sungmin    schedule 26.02.2013    source источник


Ответы (3)


Ну, я не использовал boost :: fusion, но из сообщения об ошибке и пример из документации, кажется, что for_each ожидает объект const. Т.е. operator() тоже должен быть константным. Однако вы не сможете изменить объект.

Попробуй это:

void operator()(const T& t) const {
    cout << t << endl;
}

Изменить:

Я проверил источники (v. 1.53), и декларация for_each(Sequence& seq, F const& f). Так что на самом деле нет никакого способа изменить сам объект. Единственные варианты, которые я вижу, это

либо используйте статические переменные: static int x;

или используйте указатели:

struct A {
    template <class T>
    void operator()(const T& t) const {
        (*x)++;
        std::cout << t << std::endl;
    }

    int* x;
};

int main()
{
    A a;
    a.x = new int;
    *(a.x) = 0;
    //...

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

person Alexander Malakhov    schedule 26.02.2013
comment
Спасибо. Собственно, вопрос заключается в повторении кортежа и применении объекта функции, который можно изменить. Судя по вашему ответу, я не могу использовать boost :: fusion с этой целью. Я прав? - person Sungmin; 27.02.2013

Более простой и лучший способ сделать это - использовать fusion :: fold:

#include <iostream>

#include <boost/fusion/algorithm/iteration/fold.hpp>
#include <boost/fusion/include/fold.hpp>

namespace detail {
  struct A {
    typedef int result_type;
    template<typename T1, typename T2>
    int operator()( const T1& t1, const T2& t2 ) const {
      std::cout << t1 << "," << t2 << std::endl;
      return t1 + 1;
    }
  };
}

int main() {
  boost::fusion::vector<int, int, int> tuple{3,4,5};
  boost::fusion::fold(tuple, 0, detail::A());
}

Если не считать синтаксических ошибок, это должно привести к следующему:

0,3
1,4
2,5

person Raymond Burkholder    schedule 25.11.2013

Решение представлено в документации boost :: phoenix :: lambda.

Секрет в том, чтобы выполнять различные вычисления в лямбда-функции вне вашего функтора.

#include <iostream>

#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/include/for_each.hpp>

#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/operator/arithmetic.hpp> 
#include <boost/phoenix/scope/lambda.hpp>
#include <boost/phoenix/scope/local_variable.hpp>
#include <boost/phoenix/function.hpp>
#include <boost/phoenix/fusion.hpp>

namespace detail {
  struct A_impl {
    template<typename T1, typename T2>
    void operator()( const T1& t1, const T2& t2 ) const {
      std::cout << t2 << "," << t1 << std::endl;
    }
  };
  boost::phoenix::function<A_impl> const A = A_impl();
}

int main() {
  namespace phx = boost::phoenix;
  using boost::phoenix::arg_names::arg1;
  using boost::phoenix::local_names::_a;
  boost::fusion::vector<int, int, int> tuple{3,4,5};
  boost::fusion::for_each(tuple, phx::lambda( _a = 0 )[detail::A(arg1,_a++)]);
}

Если не считать синтаксических ошибок, это должно привести к следующему:

0,3
1,4
2,5

person Raymond Burkholder    schedule 24.11.2013