boost::variant geometry algorithms assertion fails - c++

I'd like to have a std::vector of the geometries of geographic areas. Some of these areas are contiguous, and are represented by polygons. Some areas are discontiguous and are represented by multipolygons. My plan is to use a std::vector<boost::variant<polygon,multipolygon>> to take care of this discrepancy.
Both polygon and multipolygon fulfill the Geometry concept, so we should be able to call envelope on either one. That works, but I can't seem to call envelope on a variant<polygon,multipolygon>.
#include <vector>
#include <boost/variant.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
namespace bg = boost::geometry;
typedef bg::model::point<double, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef bg::model::polygon<point, true, true> polygon; //cw, closed polygon
typedef bg::model::multi_polygon<polygon> multipolygon;
typedef boost::variant<polygon,multipolygon> star_polygon;
int main(void){
polygon staunton_county;
bg::read_wkt("POLYGON ((-79.091666 38.132142, -79.09711 38.184771,"
" -79.02301 38.195777, -79.049779 38.121112, -79.091666 38.132142))",
staunton_county);
multipolygon dickson_county;
bg::read_wkt("MULTIPOLYGON (((-87.151995 36.289037, -87.146906 36.293344,"
" -87.144172 36.292142, -87.142315 36.294607, -87.139332 36.292418,"
" -87.14237199999999 36.290684, -87.151995 36.289037)),"
" ((-87.20424199999999 35.959186, -87.53453 35.993074,"
" -87.56679800000001 36.177857, -87.513533 36.334713,"
" -87.286501 36.321933, -87.17730299999999 36.314145,"
" -87.14987600000001 36.176878, -87.182573 36.049726,"
" -87.20424199999999 35.959186)))",
dickson_county);
box bb;
bg::envelope(staunton_county,bb);
std::cout << bg::dsv(bb) << std::endl;
bg::envelope(dickson_county,bb);;
std::cout << bg::dsv(bb) << std::endl;
star_polygon county;
county = staunton_county;
//bg::envelope(county,bb);
if (county.type() == typeid(polygon)){
bg::envelope(boost::get<polygon>(county),bb);
} else {
bg::envelope(boost::get<multipolygon>(county),bb);
}
std::cout << bg::dsv(bb) << std::endl;
return 0;
}
If I uncomment the line bg::envelope(county,bb);, compilation will fail the following error:
In file included from variant_envelope.cpp:4:
In file included from /usr/local/include/boost/geometry.hpp:17:
In file included from /usr/local/include/boost/geometry/geometry.hpp:35:
In file included from /usr/local/include/boost/geometry/strategies/strategies.hpp:25:
In file included from /usr/local/include/boost/geometry/strategies/intersection.hpp:22:
In file included from /usr/local/include/boost/geometry/strategies/cartesian/cart_intersect.hpp:21:
In file included from /usr/local/include/boost/geometry/algorithms/detail/assign_values.hpp:29:
In file included from /usr/local/include/boost/geometry/algorithms/append.hpp:24:
In file included from /usr/local/include/boost/geometry/geometries/concepts/check.hpp:33:
/usr/local/include/boost/geometry/algorithms/not_implemented.hpp:64:5: error:
no matching function for call to 'assertion_failed'
BOOST_MPL_ASSERT_MSG
^~~~~~~~~~~~~~~~~~~~
/usr/local/include/boost/mpl/assert.hpp:434:48: note: expanded from macro
'BOOST_MPL_ASSERT_MSG'
#define BOOST_MPL_ASSERT_MSG( c, msg, types_ ) \
^
/usr/local/include/boost/mpl/assert.hpp:428:9: note: expanded from macro '\
BOOST_MPL_ASSERT_MSG_IMPL'
...boost::mpl::assertion_failed<(c)>( BOOST_PP_CAT(mpl_assert_arg,counter)::assert_arg() ) \
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/boost/mpl/assert.hpp:59:58: note: expanded from macro '\
BOOST_MPL_AUX_ASSERT_CONSTANT'
# define BOOST_MPL_AUX_ASSERT_CONSTANT(T, expr) enum { expr }
^
/usr/local/include/boost/geometry/algorithms/not_implemented.hpp:105:7: note:
in instantiation of template class
'boost::geometry::nyi::not_implemented_error<void, void, void>' requested
here
nyi::not_implemented_error
^
/usr/local/include/boost/geometry/algorithms/envelope.hpp:90:18: note: in
instantiation of template class 'boost::geometry::not_implemented<void,
void, void>' requested here
struct envelope: not_implemented<Tag>
^
/usr/local/include/boost/geometry/algorithms/envelope.hpp:163:15: note: in
instantiation of template class
'boost::geometry::dispatch::envelope<boost::variant<boost::geometry::model::polygon<boost::geometry::model::point<double,
2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
std::allocator, std::allocator>,
boost::geometry::model::multi_polygon<boost::geometry::model::polygon<boost::geometry::model::point<double,
2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
std::allocator, std::allocator>, std::vector, std::allocator>,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>, void>'
requested here
dispatch::envelope<Geometry>::apply(geometry, mbr);
^
variant_envelope.cpp:44:13: note: in instantiation of function template
specialization
'boost::geometry::envelope<boost::variant<boost::geometry::model::polygon<boost::geometry::model::point<double,
2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
std::allocator, std::allocator>,
boost::geometry::model::multi_polygon<boost::geometry::model::polygon<boost::geometry::model::point<double,
2, boost::geometry::cs::cartesian>, true, true, std::vector, std::vector,
std::allocator, std::allocator>, std::vector, std::allocator>,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>,
boost::geometry::model::box<boost::geometry::model::point<double, 2,
boost::geometry::cs::cartesian> > >' requested here
bg::envelope(county,bb);
^
/usr/local/include/boost/mpl/assert.hpp:82:5: note: candidate function
[with C = false] not viable: no known conversion from 'boost::mpl::failed
************(boost::geometry::nyi::not_implemented_error<void, void,
void>::THIS_OPERATION_IS_NOT_OR_NOT_YET_IMPLEMENTED::************)(types<void,
void, void>)' to 'typename assert<false>::type'
(aka 'mpl_::assert<false>') for 1st argument
int assertion_failed( typename assert<C>::type );
^
1 error generated.
I don't think this is related to implicit instantiation of undefined template: Boost Bug or Clang Bug? , because I'm using boost version 1.55.0.
The if statement after the commented line is workable, but it seems like a hack. Is there a way to get it to work without resorting to enumerating the different types in the variant?

You can make a polymorphic function that dispatches on the variant using a boost::static_visitor:
static const envelope_ generic_envelope { };
// ...
generic_envelope(county,bb);
Where envelope_ is defined as:
struct envelope_ : boost::static_visitor<void> {
template <typename... T> //dispatch
void operator()(boost::variant<T...> const& v, box& bb) const {
boost::apply_visitor(boost::bind(*this, ::_1, boost::ref(bb)), v);
}
template <typename T> // relay
void operator()(T const& v, box& bb) const {
bg::envelope(v, bb);
}
};
See it Live On Coliru
Full Program
for future reference:
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
#include <boost/variant.hpp>
#include <boost/bind.hpp>
namespace bg = boost::geometry;
typedef bg::model::point<double, 2, bg::cs::cartesian> point;
typedef bg::model::box<point> box;
typedef bg::model::polygon<point, true, true> polygon; //cw, closed polygon
typedef bg::model::multi_polygon<polygon> multipolygon;
typedef boost::variant<polygon,multipolygon> star_polygon;
struct envelope_ : boost::static_visitor<void>
{
template <typename... T> //dispatch
void operator()(boost::variant<T...> const& v, box& bb) const {
boost::apply_visitor(boost::bind(*this, ::_1, boost::ref(bb)), v);
}
template <typename T> // relay
void operator()(T const& v, box& bb) const {
bg::envelope(v, bb);
}
};
int main(void){
static const envelope_ generic_envelope { };
polygon staunton_county;
bg::read_wkt("POLYGON ((-79.091666 38.132142, -79.09711 38.184771,"
" -79.02301 38.195777, -79.049779 38.121112, -79.091666 38.132142))",
staunton_county);
multipolygon dickson_county;
bg::read_wkt("MULTIPOLYGON (((-87.151995 36.289037, -87.146906 36.293344,"
" -87.144172 36.292142, -87.142315 36.294607, -87.139332 36.292418,"
" -87.14237199999999 36.290684, -87.151995 36.289037)),"
" ((-87.20424199999999 35.959186, -87.53453 35.993074,"
" -87.56679800000001 36.177857, -87.513533 36.334713,"
" -87.286501 36.321933, -87.17730299999999 36.314145,"
" -87.14987600000001 36.176878, -87.182573 36.049726,"
" -87.20424199999999 35.959186)))",
dickson_county);
box bb;
bg::envelope(staunton_county,bb);
std::cout << bg::dsv(bb) << std::endl;
bg::envelope(dickson_county,bb);;
std::cout << bg::dsv(bb) << std::endl;
star_polygon county;
county = staunton_county;
generic_envelope(county,bb);
std::cout << bg::dsv(bb) << std::endl;
}

Related

variant pixel buffer to vector using boost::apply_visitor

I am trying to convert variablepixelbuffer.vbuffer() to a vector of double values using apply_visitor in boost.
I came with this piece of code till now :
struct GetVector : public boost::static_visitor<std::vector<double>>
{
//values will be returned in a pair. double is
// used since it can contain the value for any pixel type
typedef std::vector<double> result_type;
template<typename T
void myfunction (const T& i) { // function:
result_type.push_back(static_cast<double>(*i));
}
template<typename T>
result_type
operator() (const T& v)
{
typedef typename T::element_type::value_type value_type;
std::for_each (v->data(), v->data() + v->num_elements(), myfunction);
return result_type;
}
};
/* pixel-example-start */
void
readPixelData(const FormatReader& reader,
std::ostream& stream,int x,int y,int w,int h)
{
// Change the current series to this index
reader.setSeries(0);
// Get total number of planes (for this image index)
dimension_size_type pc = reader.getImageCount();
// Pixel buffer
VariantPixelBuffer buf;
dimension_size_type xd = x;
dimension_size_type yd = y;
dimension_size_type wd = w;
dimension_size_type hd = h;
// Loop over planes (for this image index)
for (dimension_size_type p = 0 ; p < pc; p++)
{
// Read the entire plane into the pixel buffer.
reader.openBytes(p, buf,xd,yd,wd,hd);
}
GetVector visitor;
GetVector::result_type result = boost::apply_visitor(visitor, buf.vbuffer());
}
But i am getting some long errors, and some piece of it are
/usr/include/boost/variant/detail/apply_visitor_unary.hpp:60:43:
required from ‘typename Visitor::result_type
boost::apply_visitor(Visitor&, Visitable&) [with Visitor =
MinMaxVisitor; Visitable =
boost::variant >,
boost::mpl::v_item >,
boost::mpl::v_item
, boost::mpl::v_item >,
boost::mpl::v_item >,
boost::mpl::v_item >,
boost::mpl::v_item
, boost::mpl::v_item
, boost::mpl::v_item
, boost::mpl::v_item
, boost::mpl::v_item
, boost::mpl::vector0, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1>, 1> >, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>;
typename Visitor::result_type = std::vector >]’ read_subimage.C:82:85: required from here
/usr/include/c++/4.8/bits/stl_algo.h:4417:14: error: must use ‘.’ or
‘->’ to call pointer-to-member function in ‘__f (...)’, e.g. ‘(...
->* __f) (...)’
How can i reslove this, I need to get the pixel buffer data into vector .

deal with boost variant and boost function

I would like a vector to hold differents kind of boost::function, so, I tried a variant :
#include <boost/variant.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <vector>
void a(int, int)
{}
void b()
{}
int main(int argc, char **argv)
{
typedef boost::variant<boost::function0<void>, boost::function2<void, int, int>> v;
std::vector<v> c;
c.push_back(boost::bind(&a, _1, _2));
c.push_back(boost::bind(&b));
auto& function = boost::get<boost::function2<void, int, int>>(c[0]);
function(4, 5);
}
But I've this error :
/usr/local/include/boost/variant/variant.hpp:1515:28: error: call to member function 'initialize' is ambiguous
initializer::initialize(
~~~~~~~~~~~~~^~~~~~~~~~
/usr/local/include/boost/variant/variant.hpp:1692:9: note: in instantiation of function template specialization 'boost::variant<boost::function0<void>, boost::function2<void, int, int>, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>::convert_construct<boost::_bi::bind_t<void, void (*)(int, int), boost::_bi::list2<boost::arg<1>, boost::arg<2> > > >' requested here
convert_construct( detail::variant::move(operand), 1L);
^
I didn't find any help to deal with theses error
(and other compiler output)
https://ideone.com/QEdlyF
Thanks !
The constructor for Boost Function is pretty liberal in what it can accept. This results in there being no "best" constructor amongst the elements types of the variant.
You'll have to explicitly cast.
Then again, it's probably even easier to just hide the knowledge about types alltogether (since the helpful parts are ambiguous anyways) and use Boost Any.

Boolean expression using Boost

I'm trying to simply the spirit parser found in this answer:
Boolean expression (grammar) parser in c++
To remove the xor operator and logic. I'm failing to see how to do it, I tried using
expr_ = or_.alias();
or_ = (and__ >> "or" >> or_ )[ _val = phx::construct<binop<op_or >>(_1, _2) ] | and_ [ _val = _1 ];
and_ = (not_ >> "and" >> and_) [ _val = phx::construct<binop<op_and>>(_1, _2) ] | not_ [ _val = _1 ];
not_ = ("not" > simple ) [ _val = phx::construct<unop <op_not>>(_1) ] | simple [ _val = _1 ];
for the rule definitions, but I get a cryptic compiler message that I don't understand:
test\test.cpp `boost::spirit::_2' cannot appear in a constant-expression
If anyone can shed some light, I'd appreciate it.
Here is the log:
compiler: Default compiler Building Makefile:
"D:\Dev-Cpp\test\Makefile.win" Executing make... make.exe -f
"D:\Dev-Cpp\test\Makefile.win" all g++.exe -c test.cpp -o test.o
-I"D:/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"D:/Dev-Cpp/include/c++/3.4.2/backward" -I"D:/Dev-Cpp/include/c++/3.4.2/mingw32" -I"D:/Dev-Cpp/include/c++/3.4.2" -I"D:/Dev-Cpp/include"
test.cpp: In constructor `parser<It, Skipper>::parser()':
test.cpp:76: error: `boost::spirit::_1' cannot appear in a
constant-expression test.cpp:76: error: a comma operator cannot
appear in a constant-expression test.cpp:76: error:
`boost::spirit::_2' cannot appear in a constant-expression
test.cpp:76: error: `>>' should be `> >' within a nested template
argument list
test.cpp:77: error: `boost::spirit::_1' cannot appear in a
constant-expression
test.cpp:77: error: a comma operator cannot appear in a
constant-expression test.cpp:77: error: `boost::spirit::_2' cannot
appear in a constant-expression test.cpp:77: error: `>>' should be `>
>' within a nested template argument list
test.cpp:78: error: `boost::spirit::_1' cannot appear in a
constant-expression
test.cpp:78: error: `>>' should be `> >' within a nested template
argument list
test.cpp: In function `int main()': test.cpp:98: error: expected
primary-expression before "auto" test.cpp:98: error: expected `;'
before "auto"
test.cpp:111: error: expected primary-expression before ')' token
test.cpp:111: error: expected `;' before ')' token test.cpp:113:
error: ISO C++ forbids declaration of `f' with no type test.cpp:113:
error: `begin' is not a member of `std' test.cpp:113: error: `input'
undeclared (first use this function) test.cpp:113: error: (Each
undeclared identifier is reported only once for each function it
appears in.) test.cpp:113: error: ISO C++ forbids declaration of `l'
with no type test.cpp:113: error: `end' is not a member of `std'
test.cpp:114: error: `f' cannot appear in a constant-expression
test.cpp:114: error: a function call cannot appear in a
constant-expression test.cpp:114: error: template argument 1 is
invalid test.cpp:114: error: invalid type in declaration before ';'
token
test.cpp:126: error: `f' cannot appear in a constant-expression
test.cpp:126: error: a function call cannot appear in a
constant-expression test.cpp:126: error: template argument 1 is
invalid test.cpp:126: error: ISO C++ forbids declaration of `e' with
no type
test.cpp:128: error: expected primary-expression before '(' token
test.cpp:128: error: `first' has not been declared test.cpp:128:
error: request for member of non-aggregate type before ',' token
test.cpp:128: error: `last' has not been declared test.cpp:128:
error: request for member of non-aggregate type before ')' token
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h: At
global scope:
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h: In
instantiation of `std::iterator_traits<int>':
D:/Dev-Cpp/include/boost/detail/iterator.hpp:83: instantiated from
`boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:509: instantiated from
`boost::InputIterator<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:545: instantiated from
`boost::ForwardIterator<int>'
D:/Dev-Cpp/include/boost/concept/detail/has_constraints.hpp:42:
instantiated from
`boost::concepts::not_satisfied<boost::ForwardIterator<int> >'
D:/Dev-Cpp/include/boost/mpl/if.hpp:67: instantiated from
`boost::mpl::if_<boost::concepts::not_satisfied<boost::ForwardIterator<int>
>, boost::concepts::constraint<boost::ForwardIterator<int> >, boost::concepts::requirement<boost::concepts::failed************boost::ForwardIterator<int>::************>
>' D:/Dev-Cpp/include/boost/concept/detail/general.hpp:56: instantiated from `boost::concepts::requirement_<void
(*)(boost::ForwardIterator<int>)>'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:149: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type,
Attr&) [with Iterator = int, Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h:129:
error: `int' is not a class, struct, or union type
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h:130:
error: `int' is not a class, struct, or union type
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h:131:
error: `int' is not a class, struct, or union type
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h:132:
error: `int' is not a class, struct, or union type
D:/Dev-Cpp/include/c++/3.4.2/bits/stl_iterator_base_types.h:133:
error: `int' is not a class, struct, or union type
D:/Dev-Cpp/include/boost/concept_check.hpp: In instantiation of
`boost::InputIterator<int>':
D:/Dev-Cpp/include/boost/concept_check.hpp:545: instantiated from
`boost::ForwardIterator<int>'
D:/Dev-Cpp/include/boost/concept/detail/has_constraints.hpp:42:
instantiated from
`boost::concepts::not_satisfied<boost::ForwardIterator<int> >'
D:/Dev-Cpp/include/boost/mpl/if.hpp:67: instantiated from
`boost::mpl::if_<boost::concepts::not_satisfied<boost::ForwardIterator<int>
>, boost::concepts::constraint<boost::ForwardIterator<int> >, boost::concepts::requirement<boost::concepts::failed************boost::ForwardIterator<int>::************>
>' D:/Dev-Cpp/include/boost/concept/detail/general.hpp:56: instantiated from `boost::concepts::requirement_<void
(*)(boost::ForwardIterator<int>)>'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:149: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type,
Attr&) [with Iterator = int, Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/boost/concept_check.hpp:509: error: no type named
`value_type' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:510: error: no type named
`difference_type' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:511: error: no type named
`reference' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:512: error: no type named
`pointer' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:513: error: no type named
`iterator_category' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp: In function `bool
boost::spirit::qi::phrase_parse(Iterator&, Iterator, const Expr&,
const Skipper&, boost::spirit::qi::skip_flag::enum_type, Attr&) [with
Iterator = int, Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>]':
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:155: error:
conversion from
`mpl_::failed************(boost::spirit::qi::phrase_parse(Iterator&,
Iterator, const Expr&, const Skipper&,
boost::spirit::qi::skip_flag::enum_type, Attr&) [with Iterator = int,
Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_,
boost::detail::variant::void_>]::error_invalid_expression::************)(bool)'
to non-scalar type `mpl_::assert< false>' requested
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:155: error:
enumerator value for `mpl_assertion_in_line_155' not integer constant
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:164: error: request
for member `parse' in `boost::spirit::compile [with Domain =
boost::spirit::qi::domain, Expr = bool](((const bool&)(+expr)))',
which is of non-class type `bool'
D:/Dev-Cpp/include/boost/concept_check.hpp: In destructor
`boost::ForwardIterator<TT>::~ForwardIterator() [with TT = int]':
D:/Dev-Cpp/include/boost/concept/detail/general.hpp:38:
instantiated from `static void
boost::concepts::requirement<boost::concepts::failed************Model::************>::failed()
[with Model = boost::ForwardIterator<int>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:149: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type,
Attr&) [with Iterator = int, Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/boost/concept_check.hpp:548: error: no type named
`iterator_category' in `struct boost::ForwardIterator<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:548: error: `failed' is
not a member of `<declaration error>'
D:/Dev-Cpp/include/boost/concept_check.hpp:553: error: no type named
`reference' in `struct boost::InputIterator<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:554: error: no type named
`reference' in `struct boost::InputIterator<int>'
D:/Dev-Cpp/include/boost/spirit/home/qi/char/char_parser.hpp: In
member function `bool boost::spirit::qi::char_parser<Derived, Char,
Attr>::parse(Iterator&, const Iterator&, Context&, const Skipper&,
Attribute&) const [with Iterator = int, Context = const
boost::spirit::unused_type, Skipper = boost::spirit::unused_type,
Attribute = const boost::spirit::unused_type, Derived =
boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, Char = char, Attr =
char]': D:/Dev-Cpp/include/boost/spirit/home/qi/skip_over.hpp:27:
instantiated from `void boost::spirit::qi::skip_over(Iterator&, const
Iterator&, const T&) [with Iterator = int, T =
boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:169: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type,
Attr&) [with Iterator = int, Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/boost/spirit/home/qi/char/char_parser.hpp:68:
error: invalid type argument of `unary *'
D:/Dev-Cpp/include/boost/spirit/home/qi/char/char_parser.hpp:70:
error: invalid type argument of `unary *'
D:/Dev-Cpp/include/boost/concept_check.hpp: In destructor
`boost::InputIterator<TT>::~InputIterator() [with TT = int]':
D:/Dev-Cpp/include/boost/concept_check.hpp:547: instantiated from
`boost::ForwardIterator<TT>::~ForwardIterator() [with TT = int]'
D:/Dev-Cpp/include/boost/concept/detail/general.hpp:38:
instantiated from `static void
boost::concepts::requirement<boost::concepts::failed************Model::************>::failed()
[with Model = boost::ForwardIterator<int>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:149: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, boost::spirit::qi::skip_flag::enum_type,
Attr&) [with Iterator = int, Expr = bool, Skipper =
boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal,
boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space,
boost::spirit::char_encoding::standard> >, 0l>, Attr =
boost::variant<var, boost::recursive_wrapper<unop<op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_,
boost::detail::variant::void_, boost::detail::variant::void_>]'
D:/Dev-Cpp/include/boost/spirit/home/qi/parse.hpp:197: instantiated
from `bool boost::spirit::qi::phrase_parse(Iterator&, Iterator, const
Expr&, const Skipper&, Attr&) [with Iterator = int, Expr = bool,
Skipper = boost::spirit::standard::space_type, Attr = expr]'
test.cpp:119: instantiated from here
D:/Dev-Cpp/include/boost/concept_check.hpp:517: error: no type named
`difference_type' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:517: error: `failed' is
not a member of `<declaration error>'
D:/Dev-Cpp/include/boost/concept_check.hpp:518: error: no type named
`iterator_category' in `struct boost::detail::iterator_traits<int>'
D:/Dev-Cpp/include/boost/concept_check.hpp:518: error: `failed' is
not a member of `<declaration error>'
D:/Dev-Cpp/include/boost/concept_check.hpp:521: error: invalid type
argument of `unary *'
make.exe: *** [test.o] Error 1
Execution terminated
You accidentally mistyped and_ as and__.
Changing and__ to and_ will make it compile.
Here's a more cleaned up version, removing the now-unneeded declarations relating to xor:
Edit Also 'backported' for old compilers that don't know about auto, decltype, proper template parsing (>> vs. > >) etc.):
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/variant/recursive_wrapper.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
struct op_or {};
struct op_and {};
struct op_not {};
typedef std::string var;
template <typename tag> struct binop;
template <typename tag> struct unop;
typedef boost::variant<var,
boost::recursive_wrapper<unop <op_not> >,
boost::recursive_wrapper<binop<op_and> >,
boost::recursive_wrapper<binop<op_or> >
> expr;
template <typename tag> struct binop
{
explicit binop(const expr& l, const expr& r) : oper1(l), oper2(r) { }
expr oper1, oper2;
};
template <typename tag> struct unop
{
explicit unop(const expr& o) : oper1(o) { }
expr oper1;
};
struct printer : boost::static_visitor<void>
{
printer(std::ostream& os) : _os(os) {}
std::ostream& _os;
//
void operator()(const var& v) const { _os << v; }
void operator()(const binop<op_and>& b) const { print(" & ", b.oper1, b.oper2); }
void operator()(const binop<op_or >& b) const { print(" | ", b.oper1, b.oper2); }
void print(const std::string& op, const expr& l, const expr& r) const
{
_os << "(";
boost::apply_visitor(*this, l);
_os << op;
boost::apply_visitor(*this, r);
_os << ")";
}
void operator()(const unop<op_not>& u) const
{
_os << "(";
_os << "!";
boost::apply_visitor(*this, u.oper1);
_os << ")";
}
};
std::ostream& operator<<(std::ostream& os, const expr& e)
{ boost::apply_visitor(printer(os), e); return os; }
template <typename It, typename Skipper = qi::space_type>
struct parser : qi::grammar<It, expr(), Skipper>
{
parser() : parser::base_type(expr_)
{
using namespace qi;
expr_ = or_.alias();
or_ = (and_ >> "or" >> or_ ) [ _val = phx::construct<binop<op_or > >(_1, _2) ] | and_ [ _val = _1 ];
and_ = (not_ >> "and" >> and_) [ _val = phx::construct<binop<op_and> >(_1, _2) ] | not_ [ _val = _1 ];
not_ = ("not" > simple ) [ _val = phx::construct<unop <op_not> >(_1) ] | simple [ _val = _1 ];
simple = (('(' > expr_ > ')') | var_);
var_ = qi::lexeme[ +alpha ];
BOOST_SPIRIT_DEBUG_NODE(expr_);
BOOST_SPIRIT_DEBUG_NODE(or_);
BOOST_SPIRIT_DEBUG_NODE(and_);
BOOST_SPIRIT_DEBUG_NODE(not_);
BOOST_SPIRIT_DEBUG_NODE(simple);
BOOST_SPIRIT_DEBUG_NODE(var_);
}
private:
qi::rule<It, var() , Skipper> var_;
qi::rule<It, expr(), Skipper> not_, and_, or_, simple, expr_;
};
int main()
{
const std::string inputs[] = {
// From the OP:
std::string("(a and b) or ((c and d) or (a and b));"),
std::string("a and b or (c and d or a and b);"),
/// Simpler tests:
std::string("a and b;"),
std::string("a or b;"),
std::string("a or b;"),
std::string("not a;"),
std::string("not a and b;"),
std::string("not (a and b);"),
std::string("a or b or c;"),
std::string("") // marker
};
for (const std::string *i = inputs; !i->empty(); ++i)
{
typedef std::string::const_iterator It;
It f(i->begin()), l(i->end());
parser<It> p;
try
{
expr result;
bool ok = qi::phrase_parse(f,l,p > ';',qi::space,result);
if (!ok)
std::cerr << "invalid input\n";
else
std::cout << "result: " << result << "\n";
} catch (const qi::expectation_failure<It>& e)
{
std::cerr << "expectation_failure at '" << std::string(e.first, e.last) << "'\n";
}
if (f!=l) std::cerr << "unparsed: '" << std::string(f,l) << "'\n";
}
return 0;
}
Output of running this sample is
result: ((a & b) | ((c & d) | (a & b)))
result: ((a & b) | ((c & d) | (a & b)))
result: (a & b)
result: (a | b)
result: (a | b)
result: (!a)
result: ((!a) & b)
result: (!(a & b))
result: (a | (b | c))

best way to do variant visitation with lambdas

I want to inline visitation of variant types with lambdas. At the moment i have the following code:
struct Foo {
boost::variant< boost::blank , int , string , vector< int > > var;
template <typename T, typename IL , typename SL , typename VL>
void ApplyOptionals( T& ref, IL&& intOption , SL&& stringOption , VL&& vectorOption ) {
if (var.which() == 1) {
intOption( ref , boost::get< int >(var) );
} else if (var.which() ==2) {
stringOption( ref , boost::get< string>(var) );
} else if (var.which() == 3) {
vectorOption( ref , boost::get< vector< int > >(var) );
}
};
};
// ...
myFooV.ApplyOptionals(
obj,
[](Obj& o, int v) -> void { cout << "int: " << v << endl; o.value = v; },
[](Obj& o, string v) -> void{ cout << "string: " << v << endl; o.name = v; },
[](Obj& o, vector< int >& v) -> void{ v.push_back(257); cout << " vector.. has elements: " << v.size() << endl; o.ids = v; }
);
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 boost::static_visitor would do
Can i get the best of both approaches?
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.
looking at this question request for member `...' is ambiguous in g++, 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)
#include <iostream>
#include <string>
#include <vector>
#include <boost/variant.hpp>
using namespace std;
typedef boost::variant< boost::blank , int , string , vector< int > > var_t;
template <typename ReturnType, typename... Lambdas>
struct lambda_visitor : public boost::static_visitor<ReturnType>, public Lambdas... {
lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... { }
};
template <typename ReturnType>
struct lambda_visitor<ReturnType> : public boost::static_visitor<ReturnType> {
lambda_visitor() {}
};
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, Lambdas...> 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<ReturnType, Lambdas...>(lambdas...);
}
int main() {
vector< int > vit;
vit.push_back(7);
var_t myFooV = vit;
auto visitor = make_lambda_visitor<void>(
[](int v) -> void { cout << "int: " << v << endl; },
[](string& v) -> void{ cout << "string: " << v << endl; },
[](vector< int >& v) -> void{ v.push_back(27); boost::get< vector< int > >(myFooV).push_back(34); cout << " vector.. has elements: " << v.size() << endl; }
);
cout << " and for the grand finale.. " << endl;
boost::apply_visitor( visitor , myFooV );
};
This, gives me roughly a bunch of template boost errors, but the distinct part is:
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()::<lambda(std::vector<int>&)>
test2.cpp:43:47: error: main()::<lambda(std::string&)>
test2.cpp:42:55: error: main()::<lambda(int)>
boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'
This is the whole error, just in case i'm missing some other relevant info:
boost_1_46_0/boost/variant/variant.hpp: In member function ‘boost::detail::variant::invoke_visitor<Visitor>::result_type boost::detail::variant::invoke_visitor<Visitor>::internal_visit(T&, int) [with T = std::vector<int>, Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, boost::detail::variant::invoke_visitor<Visitor>::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&, VoidPtrCV, T*, mpl_::true_) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T = std::vector<int>, typename Visitor::result_type = void, mpl_::true_ = mpl_::bool_<true>]’
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&, VoidPtrCV, T*, NoBackupFlag, int) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T = std::vector<int>, NoBackupFlag = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >::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&, VoidPtrCV, mpl_::false_, NoBackupFlag, Which*, step0*) [with Which = mpl_::int_<0>, step0 = boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<4l>, boost::blank, boost::mpl::l_item<mpl_::long_<3l>, int, boost::mpl::l_item<mpl_::long_<2l>, std::basic_string<char>, boost::mpl::l_item<mpl_::long_<1l>, std::vector<int>, boost::mpl::l_end> > > > >, boost::mpl::l_iter<boost::mpl::l_end> >, Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, NoBackupFlag = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >::has_fallback_type_, typename Visitor::result_type = void, mpl_::false_ = mpl_::bool_<false>]’
boost_1_46_0/boost/variant/variant.hpp:1776:13: instantiated from ‘static typename Visitor::result_type boost::variant<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor_impl(int, int, Visitor&, VoidPtrCV) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, VoidPtrCV = void*, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, 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<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::internal_apply_visitor(Visitor&) [with Visitor = boost::detail::variant::invoke_visitor<lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> > >, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, 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<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19>::apply_visitor(Visitor&) [with Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, T0_ = boost::blank, T1 = int, T2 = std::basic_string<char>, T3 = std::vector<int>, 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&, Visitable&) [with Visitor = lambda_visitor<void, main()::<lambda(int)>, main()::<lambda(std::string&)>, main()::<lambda(std::vector<int>&)> >, Visitable = boost::variant<boost::blank, int, std::basic_string<char>, std::vector<int> >, 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()::<lambda(std::vector<int>&)>
test2.cpp:43:47: error: main()::<lambda(std::string&)>
test2.cpp:42:55: error: main()::<lambda(int)>
boost_1_46_0/boost/variant/variant.hpp:832:32: error: return-statement with a value, in function returning 'void'
conclusion:
I want to add the final version of this utility, including tests:
lambda_visitor.h
#include <boost/variant.hpp>
namespace Variant {
template <typename ReturnType, typename... Lambdas>
struct lambda_visitor;
template <typename ReturnType, typename Lambda1, typename... Lambdas>
struct lambda_visitor< ReturnType, Lambda1, Lambdas...>
: public lambda_visitor<ReturnType, Lambdas...>, public Lambda1 {
using Lambda1::operator();
using lambda_visitor< ReturnType, Lambdas...>::operator();
typedef ReturnType ReturnType_t;
lambda_visitor(Lambda1 l1, Lambdas... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
}
lambda_visitor(Lambda1 && l1, Lambdas && ... lambdas) : Lambda1(l1), lambda_visitor< ReturnType, Lambdas...> (lambdas...) {
}
};
template <typename ReturnType, typename Lambda1>
struct lambda_visitor<ReturnType, Lambda1>
: public boost::static_visitor<ReturnType>, public Lambda1 {
using Lambda1::operator();
typedef ReturnType ReturnType_t;
lambda_visitor(Lambda1 l1) : boost::static_visitor<ReturnType > (), Lambda1(l1) {
}
lambda_visitor(Lambda1 && l1) : boost::static_visitor<ReturnType > (), Lambda1(l1) {
}
};
template <typename ReturnType>
struct lambda_visitor<ReturnType> : public boost::static_visitor<ReturnType> {
typedef ReturnType ReturnType_t;
lambda_visitor() : boost::static_visitor<ReturnType > () {
}
};
template <typename ReturnType>
struct default_blank_visitor {
typedef ReturnType ReturnType_t;
inline ReturnType operator() (const boost::blank&) const {
return (ReturnType) 0;
};
};
template<>
struct default_blank_visitor<void> {
typedef void ReturnType_t;
inline void operator() (const boost::blank&) const {};
};
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, default_blank_visitor< ReturnType >, Lambdas...> make_lambda_visitor(Lambdas... lambdas) {
return
{
default_blank_visitor<ReturnType > (), lambdas...
};
// you can use the following instead if your compiler doesn't
// support list-initialization yet
//return lambda_visitor<ReturnType, default_blank_visitor<ReturnType> , Lambdas...>( default_blank_visitor<ReturnType>(), lambdas...);
};
/*
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, default_blank_visitor< ReturnType >, Lambdas...> make_lambda_visitor(Lambdas && ... lambdas) {
return
{
default_blank_visitor<ReturnType > (), lambdas...
};
// you can use the following instead if your compiler doesn't
// support list-initialization yet
//return lambda_visitor<ReturnType, default_blank_visitor<ReturnType> , Lambdas...>( default_blank_visitor<ReturnType>(), lambdas...);
};*/
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, Lambdas...> 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<ReturnType, Lambdas...>(lambdas...);
}
namespace basic_usage
{
struct Test
{
typedef boost::variant< boost::blank , int , double > variant_t;
void run()
{
variant_t a, b, c;
a = 42;
b = 3.14159265;
auto visitor = Variant::make_lambda_visitor<int>( [](int v) -> int { return v+1; } , [](double v) -> 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<int>(
[](int v) -> int { return -1; }
, [](double v) -> int { return -1; }
, [](boost::blank ) -> 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<int>(
[](boost::variant< int , double >& v) -> int { return -1; }
, [](boost::blank ) -> 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");
}
};
}
};
You could use variadic templates to take the lambdas, and build a variant visitor using inheritance. That would retain the compile time checks.
template <typename ReturnType, typename... Lambdas>
struct lambda_visitor : public static_visitor<ReturnType>, public Lambdas... {
lambda_visitor(Lambdas... lambdas) : Lambdas(lambdas)... {}
};
And a little helper function to use argument type deduction (required for lambdas):
template <typename ReturnType, typename... Lambdas>
lambda_visitor<ReturnType, Lambdas...> 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<ReturnType, Lambdas...>(lambdas...);
}
Now you can make visitors like this:
auto visitor = make_lambda_visitor<int>([](int) { return 42; },
[](std::string) { return 17; },
[](std::vector<int>) { return 23; });
Note: due to a detail of the overload resolution process that I wasn't aware of, this elegant solution causes weird ambiguity errors :(
See the follow-up question for the fix.

boost::variant and printing methods of elements in vector

std::vector< boost::variant<std::string, int> > vec;
std::string s1("abacus");
int i1 = 42;
vec.push_back(s1);
vec.push_back(i1);
std::cout << vec.at(0).size() << "\n";
when I try to run this code, I get the following error:
main.cpp:68: error: ‘class boost::variant<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_, boost::detail::variant::void_>’ has no member named ‘size’
make: *** [main.o] Error 1
however, being a string it should have a size() method. I'm not sure what is going wrong. note that replacing the last line with:
std::cout << vec.at(0) << "\n";
will print "abacus", as expected.
being a string it should have a size() method
It’s not a string – it’s a variant. You first need to tell the compiler that you know there’s a string inside – i.e. retrieve it using boost::get<std::string>(vec[0]).
Be sure to read the Boost.Variant tutorial.
You need to get the first type of this variant (which is the string), the class boost::variant which you are accessing with vector::at() has no method called size(), try something like::
boost::get<0>(vec.at(0)).size(); // I think that's the syntax....