2013-11-27 19 views
7

Ich habe versucht, mit dem BOOST_FUSION_ADAPT_STRUCT Makro zu spielen und versuchte einige naive Dinge wie Fusion verwenden, um jede beliebige Struktur zu drucken.Grenzen von BOOST_FUSION_ADAPT_STRUCT

Ausgehend von diesem example code given in the documentation konnte ich einige Operationen, die mit einer Fusionssequenz erlaubt sind, auf meiner angepassten Struktur nicht durchführen.

#include <boost/fusion/adapted.hpp> 
#include <boost/fusion/sequence/io/out.hpp> 
#include <boost/fusion/sequence/intrinsic.hpp> 
#include <boost/fusion/view.hpp> 
#include <iostream> 

namespace fuz = boost::fusion; 

namespace demo 
{ 
    struct employee 
    { 
     std::string name; 
     int age; 
    }; 
} 

// demo::employee is now a Fusion sequence 
BOOST_FUSION_ADAPT_STRUCT(
    demo::employee, 
    (std::string, name) 
    (int, age)) 

int main() 
{ 
    // tried to initialize an employee like a fusion sequence 
    // but it didnt work 
    // demo::employee e("bob", 42); 

    demo::employee e; 
    e.name = "bob"; 
    e.age = 42; 

    // Access struct members with fusion random access functions 
    // ok 
    std::cout << fuz::at_c<0>(e) << std::endl; 

    // tried to print the struct like any othe fusion sequence 
    // didnt work 
    // std::cout << e << std::endl; 

    // I made it work by using a fusion view 
    // is it the right way? 
    std::cout << fuz::as_nview<0, 1>(e) << std::endl; 
} 

Dies führt mich zu den folgenden Fragen:

  • Warum die Fusion Magik arbeitet nicht hier?

  • Verwenden einer Ansicht ist die richtige Methode zum Drucken einer angepassten Struktur?

  • Wie weit kann eine angepasste Struktur als Fusion-Sequenz verwendet werden?

Antwort

8

Von der boost::fusion Dokumentation:

Die I/O-Operatoren im Namensraum boost überlastet sind :: Fusion

Was bedeutet, dass, wenn Sie eine implizite Integration dieser operator<< wollen, Sie müssen den Namespace boost::fusion in Ihren aktuellen Namespace (:: hier) injizieren oder sie explizit verwenden.

Um es allen zu, und fügte hinzu:

using namespace boost::fusion; 

Sollte in Ihrem Fall arbeiten. Oder für eine explizite Verwendung, müssen Sie schreiben:

boost::fusion::operator<<(std::cout, e) << std::endl; 

--- EDIT ---

Nach boost::fusion ‚s-Code ein bisschen lesen, scheint es, dass Sie wegen unklarer sind die Koenigs Suche von boost::fusion::operators::operator<< die ausgewählt wird, falls Ihr Argument eine echte boost::fusion::sequence ist. Dies ist

, warum Sie nicht die boost::fusion Namespace injizieren müssen, noch explizit boost::fusion::operator<< für Typen im boost::fusion Namespace definiert nennen.

Einige Erklärungen:

Ich werde das gesamte Konzept der Koenig-Lookup (auch als Argument Dependent Lookup bekannt - ADL) nicht erklären hier, da dies nicht der Punkt ist, aber im Grunde heißt es, dass Sie ein in Fall verwenden Variable, deren Typ sich in einem Namespace befindet, dann erstreckt sich die Funktionssuche auf den Namespace dieses Parameters.

In diesem speziellen Fall definiert boost/fusion/sequence/io/out.hppboost::fusion::operator::operator<<, die dann in den Namespace boost::fusion injiziert werden.

$ cat /usr/local/include/boost/fusion/sequence/io/out.hpp 
[...] 
namespace boost { namespace fusion 
{ 
    [...] 
    namespace operators 
    { 
     template <typename Sequence> 
     inline typename 
      boost::enable_if< 
       fusion::traits::is_sequence<Sequence> 
       , std::ostream& 
      >::type // this is just a SFINAE trick to ensure 
        // the function will only be selected for 
        // actual boost::fusion::sequence 
     operator<<(std::ostream& os, Sequence const& seq) 
     { 
      return fusion::out(os, seq); // this will print out the sequence 
     } 
    } 
    using operators::operator<<; // here the operator<< is injected 
           // in boost::fusion 
}} 

Das bedeutet, dassoperator<<mit Parametern, deren Typen sind in derboost::fusionNamespace ruft die richtige Überlastung finden.

Aufrufe, die Argumente verwenden, deren Typ sich nicht in diesem Namespace befindet, lösen die richtige Überladung von operator<< nicht (das ist in Ihrem Beispiel der Fall).

Sie können dies überprüfen, indem Sie Ihren Typ im Namespace boost::fusion definieren.

namespace boost { namespace fusion { 
struct employee 
{ 
    std::string name; 
    int age; 
}; 
}} 

BOOST_FUSION_ADAPT_STRUCT(
    boost::fusion::employee, 
    (std::string, name) 
    (int, age)) 

[...] 
boost::fusion::employee e; 
std::cout << e << std::endl; // ADL will work here 

Randbemerkung: Wenn Sie diese Art von Namenssuche Probleme debuggen wollen, sollten Sie gdb verwenden. So wissen Sie immer, welche Überladung gewählt wurde. In diesem Fall:

$ cat fusion.cpp 
#include <iostream> 
#include <cstdlib> 

#include <boost/fusion/container/vector.hpp> 
#include <boost/fusion/sequence/io.hpp> 

int main(int, char**) 
{ 
    boost::fusion::vector<int, char> foo(42, '?'); 
    std::cout << foo << std::endl; 

    return EXIT_SUCCESS; 
} 

$ gdb -q ./fusion 
Reading symbols for shared libraries ... done 
(gdb) b 10 
Breakpoint 1 at 0x1000012f7: file fusion.cpp, line 10. 
(gdb) r 
Starting program: /Users/avallee/Projects/tmp/fusion 
Reading symbols for shared libraries ++............................. done 

Breakpoint 1, main (unnamed_arg=0x7fff5fbffb60, unnamed_arg=0x7fff5fbffb60) at fusion.cpp:10 
10 std::cout << foo << std::endl; 
(gdb) s 
boost::fusion::operators::operator<< <boost::fusion::vector<int, char, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > ([email protected], [email protected]) at out.hpp:38 
38    return fusion::out(os, seq); 
4

Vielen Dank Aurelien für Ihre großartige detaillierte Erklärung. Ich habe auch this post auf Google-Gruppen gefunden. Wie Ihre Erklärung dazu führen würde, ist der einfachste Weg, um Dinge zum Laufen zu bringen, in den Demonamespace zu setzen:

namespace demo{ 
    using boost::fusion::operators::operator<<; 
    ...