2011-11-09 9 views
6

Estoy usando karma para generar representaciones de estructuras grandes, pero las estructuras se están copiando durante la generación. No creo que tengan que estarlo, así que me preguntaba cómo evitarlo.Evitar copias de atributos con generadores de karma

El ejemplo rápido del ejemplo imprime "Copia", ya que la estructura de destino se copia en 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); 

puedo detener la copia declarando foo_rule 'atributo s por referencia:

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

pero eso no funciona con un vector [obviamente foo s por lo tanto se pueden copiar, pero puede ser barato copiar en la construcción del vector, pero es caro copiar en el momento de generar :-)]

El siguiente ejemplo imprime 'Copiar' cinco veces durante la generación (es decir, ignorando las copias durante el vector ctor); 10 veces si el atributo foo_rule 's no es una referencia:

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

Tener ambas normas tienen referencias no se compila con Boost 1,47 VC en 2008. Es decir, con:

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

consigo extract_from_container instanciado con Attribute = std::vector<foo> y Exposed=std::vector<foo> &. En la línea 131 de extract_from.hpp, intenta formar Exposed const & y el compilador falla al crear refrence-to-reference.

Siento que me falta algo, ¡así que cualquier apuntador sería muy apreciado!

+1

+1 para una excelente problema mínima. Tal vez, podrías hacer que sea aún más copiable/adaptable (en este momento, las personas que no tengan un conocimiento íntimo de Spirit probablemente no lo ejecuten). Probé mi respuesta, y la publicación contiene una muestra mínima completa. Cheers – sehe

Respuesta

3

Estoy seguro de que lo has probado, pero lo diré de todos modos. ¿Ha tratado de la siguiente manera:

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

actualización acabo probado con el siguiente fragmento (g ++ 4.6 con Boost 1.47.0). Confirma que lo anterior funciona. Sin embargo, hay margen para la confusión, ya que el std::vector<foo> my_vec_foo(5) también mostrará que se hicieron 5 copias. Vea la carta de gran advertencia en el código y la salida:

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

Salida:

Copy! 
Copy! 
Copy! 
Copy! 
Copy! 

START WATCHING NOW 
+0

Las cinco copias deben ser claras, ya que así es como funcionan el tamaño (y el ctor especial). Prefieren construir un elemento como el segundo parámetro y copiarlo en todas las ranuras reservadas. – Xeo

+0

@Xeo: ¿crees que debería haberlo explicado? Pensé que era obvio :) – sehe

+0

Solo quería señalarlo a cualquiera que se esté preguntando. :) Además, su ejemplo no incluye algunos includes y no parece compilarse en Ideone. Parece que la versión de Boost que usan es muy baja. – Xeo

Cuestiones relacionadas