Note that there are some explanatory texts on larger screens.

plurals
  1. POC++ Boost recursive variant overloading apply_visitor
    primarykey
    data
    text
    <p>abstract: I am looking to overload the apply_visitor() method in a class that contains a recursive boost::variant object.</p> <p>In the code included below there is the method:</p> <pre><code>template &lt;typename T&gt; ostream&amp; apply_visitor(const T&amp; fn) const </code></pre> <p>I would like to overload this method for different visitors. Something like this:</p> <pre><code>ostream&amp; apply_visitor(const PrintData&amp; fn) const </code></pre> <p>But the problem is that the class PrintData is not yet complete (see comments in the code below). It is defined after the Node class. So I have two questions (among others -- I would welcome a general critique on this code which is modeling something I'd like to put into production).</p> <p>1) Is there a way to get apply_visitor(PrintData&amp;) to work?</p> <p>2) Can I rearrange the (recursive) variant so all visitor methods are in PrintData and I wouldn't have to add apply_visitor to the Node class?</p> <pre class="lang-cpp prettyprint-override"><code>/** * compiled with gcc (tested with 4.7.2 on linux) * requires the boost development headers to be discoverable * by the compiler. * * g++ -otest-recursive-visit -std=c++11 test-recursive-visit.cpp * ./test-recursive-visit **/ #include &lt;iostream&gt; #include &lt;map&gt; #include &lt;string&gt; #include &lt;vector&gt; #include "boost/variant.hpp" #include "boost/variant/recursive_wrapper.hpp" #include "boost/variant/static_visitor.hpp" using namespace std; /// type name demangler (as implemented in g++). For other compilers, /// we could add more #elif statements, but for now, just return /// the mangled name. #ifdef __GNUG__ /// compiler is g++ #include &lt;cxxabi.h&gt; string type_demangle(const string&amp; name) { int status; char* res = abi::__cxa_demangle( name.c_str(), NULL, NULL, &amp;status); string demangled_name((status==0) ? res : name); free(res); return demangled_name; } #else /// compiler is not g++ string type_demangle(const string&amp; name) { return name; } #endif /// forward declaration of the Node class /// (needed for recursive variant type) class Node; /// the actual recursive variant type /// (typically hidden from the users) typedef boost::variant&lt; boost::recursive_wrapper&lt;Node&gt;, vector&lt;int&gt;, vector&lt;float&gt; &gt; data_t; // forward declaration for PrintData. See note below concerning // Node::apply_visitor() class PrintData; /// this is the object users will see /// for prototyping, the tree object is public class Node { public: /// sub-nodes are identified by unique strings /// which point to one of the objects that data_t /// can hold map&lt;string,data_t&gt; tree; /// constructor for a std::map object, passed to tree Node(const initializer_list&lt;pair&lt;const string,data_t&gt;&gt;&amp; l) : tree(l) {} // // INTERESTING PART OF THIS EXAMPLE IS HERE // // I tried to replace T&amp; with PrintData&amp; adding // a forward declaration at the top but I get the // errors: // // line 86: // invalid use of incomplete type ‘const class PrintData’ // line 53: // forward declaration of ‘const class PrintData’ // /// This is called by boost::apply_visitor(Visitor(),Node) //ostream&amp; apply_visitor(const PrintData&amp; fn) const template &lt;typename T&gt; ostream&amp; apply_visitor(const T&amp; fn) const { for (auto i : tree) { *fn.os &lt;&lt; fn.prefix &lt;&lt; i.first; i.second.apply_visitor(fn); } return *fn.os; } }; /// the printing visitor to ostream object class PrintData : public boost::static_visitor&lt;ostream&amp;&gt; { public: ostream* os; string prefix; /// keep a pointer to the ostream and keep /// a prefix string which will hold and "indent" /// which is something like " " for every level /// of recursion PrintData(ostream&amp; out_stream, const string&amp; prefix_str="") : os(&amp;out_stream) , prefix(prefix_str) {} /// recurse into the tree, adding indent characters to prefix ostream&amp; operator()(Node&amp; n) const { *os &lt;&lt; endl; n.apply_visitor(PrintData(*os, prefix+" ")); *os; } /// actual data types that we want to print out template &lt;typename T&gt; ostream&amp; operator()(const vector&lt;T&gt;&amp; d) const { *os &lt;&lt; " (vector&lt;" &lt;&lt; type_demangle(typeid(T).name()) &lt;&lt; "&gt;):"; for (T i : d) { *os &lt;&lt; " " &lt;&lt; i; } *os &lt;&lt; endl; return *os; } }; /// convenience operator to allow: cout &lt;&lt; node; ostream&amp; operator&lt;&lt;(ostream&amp; os, const Node&amp; n) { return boost::apply_visitor(PrintData(os), n); } int main() { /// hooray for initialization lists!!! Node n { {"X", Node{ {"a", vector&lt;int&gt;{1,2,3}}, {"b", vector&lt;float&gt;{2,3,4}} }}, {"Y", vector&lt;int&gt;{3,4,5}}, {"Z", Node{ {"A", Node{ {"c", vector&lt;float&gt;{4,5,6}} }} }} }; /** applying PrintData to n prints out the following: X a (vector&lt;int&gt;): 1 2 3 b (vector&lt;float&gt;): 2 3 4 Y (vector&lt;int&gt;): 3 4 5 Z A c (vector&lt;float&gt;): 4 5 6 **/ cout &lt;&lt; n; } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload