Note that there are some explanatory texts on larger screens.

plurals
  1. PObest way to do variant visitation with lambdas
    primarykey
    data
    text
    <p>I want to inline visitation of variant types with lambdas. At the moment i have the following code:</p> <pre><code>struct Foo { boost::variant&lt; boost::blank , int , string , vector&lt; int &gt; &gt; var; template &lt;typename T, typename IL , typename SL , typename VL&gt; void ApplyOptionals( T&amp; ref, IL&amp;&amp; intOption , SL&amp;&amp; stringOption , VL&amp;&amp; vectorOption ) { if (var.which() == 1) { intOption( ref , boost::get&lt; int &gt;(var) ); } else if (var.which() ==2) { stringOption( ref , boost::get&lt; string&gt;(var) ); } else if (var.which() == 3) { vectorOption( ref , boost::get&lt; vector&lt; int &gt; &gt;(var) ); } }; }; // ... myFooV.ApplyOptionals( obj, [](Obj&amp; o, int v) -&gt; void { cout &lt;&lt; "int: " &lt;&lt; v &lt;&lt; endl; o.value = v; }, [](Obj&amp; o, string v) -&gt; void{ cout &lt;&lt; "string: " &lt;&lt; v &lt;&lt; endl; o.name = v; }, [](Obj&amp; o, vector&lt; int &gt;&amp; v) -&gt; void{ v.push_back(257); cout &lt;&lt; " vector.. has elements: " &lt;&lt; v.size() &lt;&lt; endl; o.ids = v; } ); </code></pre> <p>However the main drawback of this approach is that it depends on the order of variant type parameters and doesn't detect at compile-time unhandled types like <code>boost::static_visitor</code> would do</p> <p>Can i get the best of both approaches?</p> <hr> <p>Working on the excellent answer from RMartinho, i'm trying to work out this error, it seems that variant thinks the operator() calls are amibiguous (i'm using g++ 4.5.1, it's like it couldn't see the lambda operators.</p> <p>looking at this question <a href="https://stackoverflow.com/questions/1313063/request-for-member-is-ambiguous-in-g">request for member `...&#39; is ambiguous in g++</a>, it seems that c++ doesn't like multiple inheritance as a way to provide multiple overloads (even if the calls are completely non-ambiguous because of different signature)</p> <pre><code>#include &lt;iostream&gt; #include &lt;string&gt; #include &lt;vector&gt; #include &lt;boost/variant.hpp&gt; using namespace std; typedef boost::variant&lt; boost::blank , int , string , vector&lt; int &gt; &gt; var_t; template &lt;typename ReturnType, typename... Lambdas&gt; struct lambda_visitor : public boost::static_visitor&lt;ReturnType&gt;, public Lambdas... { lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... { } }; template &lt;typename ReturnType&gt; struct lambda_visitor&lt;ReturnType&gt; : public boost::static_visitor&lt;ReturnType&gt; { lambda_visitor() {} }; template &lt;typename ReturnType, typename... Lambdas&gt; lambda_visitor&lt;ReturnType, Lambdas...&gt; make_lambda_visitor(Lambdas... lambdas) { return { lambdas... }; // you can use the following instead if your compiler doesn't // support list-initialization yet // return lambda_visitor&lt;ReturnType, Lambdas...&gt;(lambdas...); } int main() { vector&lt; int &gt; vit; vit.push_back(7); var_t myFooV = vit; auto visitor = make_lambda_visitor&lt;void&gt;( [](int v) -&gt; void { cout &lt;&lt; "int: " &lt;&lt; v &lt;&lt; endl; }, [](string&amp; v) -&gt; void{ cout &lt;&lt; "string: " &lt;&lt; v &lt;&lt; endl; }, [](vector&lt; int &gt;&amp; v) -&gt; void{ v.push_back(27); boost::get&lt; vector&lt; int &gt; &gt;(myFooV).push_back(34); cout &lt;&lt; " vector.. has elements: " &lt;&lt; v.size() &lt;&lt; endl; } ); cout &lt;&lt; " and for the grand finale.. " &lt;&lt; endl; boost::apply_visitor( visitor , myFooV ); }; </code></pre> <p>This, gives me roughly a bunch of template boost errors, but the distinct part is:</p> <pre class="lang-none prettyprint-override"><code>boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous test2.cpp:44:54: error: candidates are: main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; test2.cpp:43:47: error: main()::&lt;lambda(std::string&amp;)&gt; test2.cpp:42:55: error: main()::&lt;lambda(int)&gt; boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void' </code></pre> <p>This is the whole error, just in case i'm missing some other relevant info:</p> <pre class="lang-none prettyprint-override"><code>boost_1_46_0/boost/variant/variant.hpp: In member function ‘boost::detail::variant::invoke_visitor&lt;Visitor&gt;::result_type boost::detail::variant::invoke_visitor&lt;Visitor&gt;::internal_visit(T&amp;, int) [with T = std::vector&lt;int&gt;, Visitor = lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt;, boost::detail::variant::invoke_visitor&lt;Visitor&gt;::result_type = void]’: boost_1_46_0/boost/variant/detail/visitation_impl.hpp:130:9: instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke_impl(int, Visitor&amp;, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor&lt;lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt; &gt;, VoidPtrCV = void*, T = std::vector&lt;int&gt;, typename Visitor::result_type = void, mpl_::true_ = mpl_::bool_&lt;true&gt;]’ boost_1_46_0/boost/variant/detail/visitation_impl.hpp:173:9: instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl_invoke(int, Visitor&amp;, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor&lt;lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt; &gt;, VoidPtrCV = void*, T = std::vector&lt;int&gt;, NoBackupFlag = boost::variant&lt;boost::blank, int, std::basic_string&lt;char&gt;, std::vector&lt;int&gt; &gt;::has_fallback_type_, typename Visitor::result_type = void]’ boost_1_46_0/boost/variant/detail/visitation_impl.hpp:260:1: instantiated from ‘typename Visitor::result_type boost::detail::variant::visitation_impl(int, int, Visitor&amp;, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_&lt;0&gt;, step0 = boost::detail::variant::visitation_impl_step&lt;boost::mpl::l_iter&lt;boost::mpl::l_item&lt;mpl_::long_&lt;4l&gt;, boost::blank, boost::mpl::l_item&lt;mpl_::long_&lt;3l&gt;, int, boost::mpl::l_item&lt;mpl_::long_&lt;2l&gt;, std::basic_string&lt;char&gt;, boost::mpl::l_item&lt;mpl_::long_&lt;1l&gt;, std::vector&lt;int&gt;, boost::mpl::l_end&gt; &gt; &gt; &gt; &gt;, boost::mpl::l_iter&lt;boost::mpl::l_end&gt; &gt;, Visitor = boost::detail::variant::invoke_visitor&lt;lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt; &gt;, VoidPtrCV = void*, NoBackupFlag = boost::variant&lt;boost::blank, int, std::basic_string&lt;char&gt;, std::vector&lt;int&gt; &gt;::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_&lt;false&gt;]’ boost_1_46_0/boost/variant/variant.hpp:1776:13: instantiated from ‘static typename Visitor::result_type boost::variant&lt;T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19&gt;::internal_apply_visitor_impl(int, int, Visitor&amp;, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor&lt;lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt; &gt;, VoidPtrCV = void*, T0_ = boost::blank, T1 = int, T2 = std::basic_string&lt;char&gt;, T3 = std::vector&lt;int&gt;, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’ boost_1_46_0/boost/variant/variant.hpp:1787:13: instantiated from ‘typename Visitor::result_type boost::variant&lt;T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19&gt;::internal_apply_visitor(Visitor&amp;) [with Visitor = boost::detail::variant::invoke_visitor&lt;lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt; &gt;, T0_ = boost::blank, T1 = int, T2 = std::basic_string&lt;char&gt;, T3 = std::vector&lt;int&gt;, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’ boost_1_46_0/boost/variant/variant.hpp:1810:52: instantiated from ‘typename Visitor::result_type boost::variant&lt;T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19&gt;::apply_visitor(Visitor&amp;) [with Visitor = lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt;, T0_ = boost::blank, T1 = int, T2 = std::basic_string&lt;char&gt;, T3 = std::vector&lt;int&gt;, T4 = boost::detail::variant::void_, T5 = boost::detail::variant::void_, T6 = boost::detail::variant::void_, T7 = boost::detail::variant::void_, T8 = boost::detail::variant::void_, T9 = boost::detail::variant::void_, T10 = boost::detail::variant::void_, T11 = boost::detail::variant::void_, T12 = boost::detail::variant::void_, T13 = boost::detail::variant::void_, T14 = boost::detail::variant::void_, T15 = boost::detail::variant::void_, T16 = boost::detail::variant::void_, T17 = boost::detail::variant::void_, T18 = boost::detail::variant::void_, T19 = boost::detail::variant::void_, typename Visitor::result_type = void]’ boost_1_46_0/boost/variant/detail/apply_visitor_unary.hpp:60:43: instantiated from ‘typename Visitor::result_type boost::apply_visitor(Visitor&amp;, Visitable&amp;) [with Visitor = lambda_visitor&lt;void, main()::&lt;lambda(int)&gt;, main()::&lt;lambda(std::string&amp;)&gt;, main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; &gt;, Visitable = boost::variant&lt;boost::blank, int, std::basic_string&lt;char&gt;, std::vector&lt;int&gt; &gt;, typename Visitor::result_type = void]’ test2.cpp:49:40: instantiated from here boost_1_46_0/boost/variant/variant.hpp:832:32: error: request for member ‘operator()’ is ambiguous test2.cpp:44:54: error: candidates are: main()::&lt;lambda(std::vector&lt;int&gt;&amp;)&gt; test2.cpp:43:47: error: main()::&lt;lambda(std::string&amp;)&gt; test2.cpp:42:55: error: main()::&lt;lambda(int)&gt; boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void' </code></pre> <h2>conclusion:</h2> <p>I want to add the final version of this utility, including tests:</p> <h2>lambda_visitor.h</h2> <pre class="lang-c++ prettyprint-override"><code>#include &lt;boost/variant.hpp&gt; namespace Variant { template &lt;typename ReturnType, typename... Lambdas&gt; struct lambda_visitor; template &lt;typename ReturnType, typename Lambda1, typename... Lambdas&gt; struct lambda_visitor&lt; ReturnType, Lambda1, Lambdas...&gt; : public lambda_visitor&lt;ReturnType, Lambdas...&gt;, public Lambda1 { using Lambda1::operator(); using lambda_visitor&lt; ReturnType, Lambdas...&gt;::operator(); typedef ReturnType ReturnType_t; lambda_visitor(Lambda1 l1, Lambdas... lambdas) : Lambda1(l1), lambda_visitor&lt; ReturnType, Lambdas...&gt; (lambdas...) { } lambda_visitor(Lambda1 &amp;&amp; l1, Lambdas &amp;&amp; ... lambdas) : Lambda1(l1), lambda_visitor&lt; ReturnType, Lambdas...&gt; (lambdas...) { } }; template &lt;typename ReturnType, typename Lambda1&gt; struct lambda_visitor&lt;ReturnType, Lambda1&gt; : public boost::static_visitor&lt;ReturnType&gt;, public Lambda1 { using Lambda1::operator(); typedef ReturnType ReturnType_t; lambda_visitor(Lambda1 l1) : boost::static_visitor&lt;ReturnType &gt; (), Lambda1(l1) { } lambda_visitor(Lambda1 &amp;&amp; l1) : boost::static_visitor&lt;ReturnType &gt; (), Lambda1(l1) { } }; template &lt;typename ReturnType&gt; struct lambda_visitor&lt;ReturnType&gt; : public boost::static_visitor&lt;ReturnType&gt; { typedef ReturnType ReturnType_t; lambda_visitor() : boost::static_visitor&lt;ReturnType &gt; () { } }; template &lt;typename ReturnType&gt; struct default_blank_visitor { typedef ReturnType ReturnType_t; inline ReturnType operator() (const boost::blank&amp;) const { return (ReturnType) 0; }; }; template&lt;&gt; struct default_blank_visitor&lt;void&gt; { typedef void ReturnType_t; inline void operator() (const boost::blank&amp;) const {}; }; template &lt;typename ReturnType, typename... Lambdas&gt; lambda_visitor&lt;ReturnType, default_blank_visitor&lt; ReturnType &gt;, Lambdas...&gt; make_lambda_visitor(Lambdas... lambdas) { return { default_blank_visitor&lt;ReturnType &gt; (), lambdas... }; // you can use the following instead if your compiler doesn't // support list-initialization yet //return lambda_visitor&lt;ReturnType, default_blank_visitor&lt;ReturnType&gt; , Lambdas...&gt;( default_blank_visitor&lt;ReturnType&gt;(), lambdas...); }; /* template &lt;typename ReturnType, typename... Lambdas&gt; lambda_visitor&lt;ReturnType, default_blank_visitor&lt; ReturnType &gt;, Lambdas...&gt; make_lambda_visitor(Lambdas &amp;&amp; ... lambdas) { return { default_blank_visitor&lt;ReturnType &gt; (), lambdas... }; // you can use the following instead if your compiler doesn't // support list-initialization yet //return lambda_visitor&lt;ReturnType, default_blank_visitor&lt;ReturnType&gt; , Lambdas...&gt;( default_blank_visitor&lt;ReturnType&gt;(), lambdas...); };*/ template &lt;typename ReturnType, typename... Lambdas&gt; lambda_visitor&lt;ReturnType, Lambdas...&gt; make_lambda_visitor_override_blank(Lambdas... lambdas) { return { lambdas... }; // you can use the following instead if your compiler doesn't // support list-initialization yet //return lambda_visitor&lt;ReturnType, Lambdas...&gt;(lambdas...); } namespace basic_usage { struct Test { typedef boost::variant&lt; boost::blank , int , double &gt; variant_t; void run() { variant_t a, b, c; a = 42; b = 3.14159265; auto visitor = Variant::make_lambda_visitor&lt;int&gt;( [](int v) -&gt; int { return v+1; } , [](double v) -&gt; int { return (int)v*2; } ); int result = boost::apply_visitor(visitor, a); HAssertMsg( result == (42 + 1) , "unexpected"); result = boost::apply_visitor( visitor , b); HAssertMsg( result == 6 , "unexpected"); auto blankVisitor = Variant::make_lambda_visitor_override_blank&lt;int&gt;( [](int v) -&gt; int { return -1; } , [](double v) -&gt; int { return -1; } , [](boost::blank ) -&gt; int { return 0;} ); result = boost::apply_visitor( blankVisitor , c); HAssertMsg( result == 0 , "unexpected"); //same as previous case, but using lambda coalescing :-) auto blankVisitor2 = Variant::make_lambda_visitor_override_blank&lt;int&gt;( [](boost::variant&lt; int , double &gt;&amp; v) -&gt; int { return -1; } , [](boost::blank ) -&gt; int { return 0;} ); result = boost::apply_visitor( blankVisitor2 , c); HAssertMsg( result == 0 , "unexpected"); result = boost::apply_visitor( blankVisitor2 , a); HAssertMsg( result == -1 , "unexpected"); result = boost::apply_visitor( blankVisitor2 , b); HAssertMsg( result == -1 , "unexpected"); } }; } }; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    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