Как избежать копирования атрибутов с помощью генераторов кармы - PullRequest
6 голосов
/ 09 ноября 2011

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

В приведенном ниже быстром примере напечатано "Копировать!", Поскольку целевая структура копируется в rule::generate:

namespace karma = spirit::karma;
namespace phoenix = boost::phoenix;

struct foo
{
    foo() { }
    foo( foo const &other ) { std::cout << "Copy!"; }
    int f() const { return 42; }
};

std::string output;
typedef std::back_insert_iterator< std::string > iterator;
karma::rule< iterator, foo() > foo_rule = 
    karma::int_[ karma::_1 = phoenix::bind( &foo::f, karma::_val ) ];
foo my_foo;
iterator it( output );
karma::generate( it, foo_rule, my_foo );

Я могу остановить копирование, объявив атрибут foo_rule по ссылке:

karma::rule< iterator, foo &() > foo_rule

, но это не работает с вектором [очевидно, fooСледовательно, они могут быть скопированы, но могут быть дешевыми для копирования при векторном построении, но дорогими для копирования во время генерации: -)]

В приведенном ниже примере напечатано «Копировать!»пять раз во время генерации (то есть игнорирование копий во время векторного ctor);10 раз, если атрибут foo_rule не является ссылкой:

std::vector<foo> my_vec_foo(5);
karma::rule< iterator, std::vector<foo>() > vec_foo_rule = *foo_rule;
karma::generate(it, vec_foo_rule, my_vec_foo);

Наличие обоих правил для ссылок не компилируется с Boost 1.47 в VC 2008. То есть с:

karma::rule< iterator, foo &() > foo_rule /* = ... */;
karma::rule< iterator, std::vector<foo> &() > vec_foo_rule /* = ... */;

Я получаю extract_from_container, созданный с Attribute = std::vector<foo> и Exposed=std::vector<foo> &.В строке 131 файла extract_from.hpp он пытается сформировать Exposed const &, и при создании ссылки на ссылку происходит сбой компилятора.

Мне кажется, что я что-то упустил, поэтому любые указатели будут очень благодарны!

1 Ответ

3 голосов
/ 10 ноября 2011

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

std::vector<foo> my_vec_foo(5);
karma::rule< iterator, std::vector<foo>&() > vec_foo_rule = *foo_rule;
karma::generate(it, vec_foo_rule, my_vec_foo);

Обновление Я только что проверил его с помощью приведенного ниже фрагмента (g ++ 4.6 с Boost 1.47.0).Это подтверждает, что вышесказанное работает.Однако здесь есть место для путаницы, так как std::vector<foo> my_vec_foo(5) также покажет, что делается 5 копий.См. Предупреждение BIG LETTER в коде и вывод:

#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace karma = boost::spirit::karma;
namespace phoenix = boost::phoenix;

struct foo
{
    foo() { }
    foo( foo const &other ) { std::cerr << "Copy!\n"; }
    int f() const { return 42; }
};

int main()
{
    std::string output;
    typedef std::back_insert_iterator< std::string > iterator;
    iterator it( output );
    karma::rule< iterator, foo&() > foo_rule = 
        karma::int_[ karma::_1 = phoenix::bind( &foo::f, karma::_val ) ];

    foo my_foo;
    karma::generate( it, foo_rule, my_foo );

    std::vector<foo> my_vec_foo(5);

    std::cerr << "\nSTART WATCHING NOW" << std::endl;

    karma::rule< iterator, std::vector<foo>&() > vec_foo_rule = *foo_rule;
    karma::generate(it, vec_foo_rule, my_vec_foo);
}

Выход:

Copy!
Copy!
Copy!
Copy!
Copy!

START WATCHING NOW
...