Avoiding attribute copies with karma generators

I use karma to generate representations of large structures, but structures are copied during generation. I do not think that they should be, so it was interesting how to avoid this.

The short example below prints “Copy!” Because the target structure is copied to 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 ); 

I can stop the copy by declaring the foo_rule attribute at the link:

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

but this does not work with the vector [obviously, foo , therefore, can be copied, but it can be cheap to copy when building a vector, but expensive to copy when generating time :-)]

In the example below, "Copy!" Is printed. five times during generation (i.e. ignoring copies during the ctor vector); 10 times if the foo_rule attribute foo_rule not a link:

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

Having both rules, the links do not compile with Boost 1.47 on VC 2008. That is, using

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

I get extract_from_container created using Attribute = std::vector<foo> and Exposed=std::vector<foo> & . On line 131 of extract_from.hpp, it tries to form an Exposed const & , and the compiler does not work when creating a refrence-to-reference.

It seems to me that I missed something, so any pointers will be very grateful!

+6
source share
1 answer

I’m sure you tried it, but I’ll say it anyway. Have you tried the following:

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

Update I just tested it using the snippet below (g ++ 4.6 with Boost 1.47.0). This confirms that it works. However, there is room for confusion, since std::vector<foo> my_vec_foo(5) will also show 5 copies. See BIG LETTER warning in code and output:

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

Conclusion:

 Copy! Copy! Copy! Copy! Copy! START WATCHING NOW 
+3
source

Source: https://habr.com/ru/post/901116/


All Articles