I have a lot of rules that look like this:
cmd_BC = (dlm > timestamp > dlm > cid > dlm > double_)
[
_val = lazy_shared<dc::BoardControl>(_1, _2, _3)
];
I want to make it more readable, like:
cmd_BC = param(timestamp) > param(cid) > param(double_)
or even
cmd_BC = params(timestamp, cid, double_)
As sehe pointed out, it boils down to having some means to automatically expect the delimiters. What are the options here? Myself, I see three possibilities, all flawed:
Use a macro. This wouldn't allow for the shorter variadic form.
Write a custom prefix directive. I don't seem to have enough experience in Spirit's clockwork, but if it's actually not that hard, I will try to.
Write a wrapper function. I tried to no luck the following code:
template <typename T>
auto param(const T & parser) -> decltype(qi::lit(dlm) > parser)
{
return qi::lit(dlm) > parser;
}
but it doesn't compile, failing at
// report invalid argument not found (N is out of bounds)
BOOST_SPIRIT_ASSERT_MSG(
(N < sequence_size::value),
index_is_out_of_bounds, ());
I also tried to return (...).alias(), but it didn't compile too.
This solution is not very "spirit-y" and unfortunately "requires C++11" (I'm not sure how to get the required result type in c++03) but it seems to work. Inspired by the example here.
PS: Oh I didn't see your edit. You have almost the same example.
Update: Added another test using a semantic action with _1,_2 and _3
Update2: Changed the signature of operator() and operator[] following vines's advice in the comments.
Update 3: Added a variadic operator() that constructs a combined parser, and removed operator[] after finding a better solution with boost::proto. Changed slightly the examples.
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/proto/proto.hpp>
namespace qi = boost::spirit::qi;
namespace proto = boost::proto;
namespace phx = boost::phoenix;
using namespace boost::proto;
//This is a proto grammar/transform that creates the prefixed parser. The parser created depends on the parser passed (if it's a kleene or not)
// in _make_xxx "_" corresponds to the supplied parser and "_state" to the delimiter
struct CreatePrefixedParser: //you can use _make_greater instead of _make_shift_right if you want to use "expectation"
or_ <
when < dereference<_>, //If it's a kleene parser...
_make_shift_right ( //create the parser -> dlm >> *(parser -dlm)
_state,
_make_dereference (
_make_minus ( _child_c<0> ( _ ),
_state ) ) ) > ,
when < unary_plus<_>, //If it's a +parser
_make_shift_right ( //create the parser -> dlm >> +(parser -dlm)
_state,
_make_unary_plus (
_make_minus ( _child_c<0> ( _ ),
_state ) ) ) > ,
otherwise < //if it's any other parser
_make_shift_right ( //create the parser -> dlm >> (parser -dlm)
_state,
_make_minus ( _,
_state ) ) >
> {};
//-------------------------------------------------------------
//this combines the parsers this way: parser1, parser2, parser3, parser4 -> parser1>>(parser2 >>(parser3 >> parser4)))
//you can use make_expr<tag::greater> if you want to use "expectation"
//I have absolutely no idea when "deep_copy" is required but it seems to work this way
template<typename Delim, typename First, typename ... Rest>
struct myparser
{
static auto combine ( Delim dlm_, const First& first, const Rest&...rest ) ->
decltype ( make_expr<tag::shift_right> ( CreatePrefixedParser() ( deep_copy ( first ), dlm_ ), myparser<Delim, Rest...>::combine ( dlm_, rest... ) ) )
{
return make_expr<tag::shift_right> ( CreatePrefixedParser() ( deep_copy ( first ), dlm_ ), myparser<Delim, Rest...>::combine ( dlm_, rest... ) );
}
};
template<typename Delim, typename Last>
struct myparser<Delim, Last>
{
static auto combine ( Delim dlm_, const Last& last ) -> decltype ( CreatePrefixedParser() ( deep_copy ( last ), dlm_ ) )
{
return CreatePrefixedParser() ( deep_copy ( last ), dlm_ );
}
};
//-----------------------------------------------------------------
template <typename T>
struct prefixer
{
T dlm_;
prefixer ( T dlm ) : dlm_ ( dlm ) {}
template <typename ... Args>
auto operator() ( const Args&... args ) ->
decltype ( deep_copy ( myparser<T, Args...>::combine ( dlm_, args... ) ) )
{
return deep_copy ( myparser<T, Args...>::combine ( dlm_, args... ) );
}
};
template <typename T>
prefixer<T> make_prefixer ( T dlm )
{
return prefixer<T> ( dlm );
}
int main()
{
std::string test = "lameducklamedog";
std::string::const_iterator f ( test.begin() ), l ( test.end() );
auto param = make_prefixer ( qi::lit ( "lame" ) );
qi::rule<std::string::const_iterator> dog = qi::lit ( "do" ) > qi::char_ ( 'g' );
//qi::rule<std::string::const_iterator> duck = qi::lit ( "duck" ) | qi::int_;
qi::rule<std::string::const_iterator,std::string()> quackdog = (param (*qi::alpha) >> param( dog ));
std::string what;
if ( qi::parse ( f, l, quackdog, what ) && f == l )
std::cout << "the duck and the dog are lame, specially the " << what << std::endl;
else
std::cerr << "Uhoh\n" << std::string(f,l) << std::endl;
test = "*-*2.34*-*10*-*0.16*-*12.5";
std::string::const_iterator f2 ( test.begin() ), l2 ( test.end() );
auto param2 = make_prefixer ( qi::lit ( "*-*" ) );
double d;
qi::rule<std::string::const_iterator> myrule = ( param2 ( qi::double_, qi::int_, qi::double_ , qi::double_) ) [phx::ref ( d ) = qi::_1 + qi::_2 + qi::_3 + qi::_4];
if ( qi::parse ( f2, l2, myrule ) && f2 == l2 )
std::cout << "the sum of the numbers is " << d << std::endl;
else
std::cerr << "Uhoh\n";
}
If I understand correctly, you are looking for a way to automatically expect or ignore the delimiter expression (dlm)?
Skippers
This is the classic terrain for Skippers in Spirit. This is especially useful if the delimiter is variable, e.g. whitespace (varying amounts of whitespace acceptable);
bool ok = qi::phrase_parse(
first, last, // input iterators
timestamp > cid > double_, // just specify the expected params
qi::space); // delimiter, e.g. any amount of whitespace
Note the use of phrase_parse to enable grammars with skippers.
Delimited with % parser directive
You could explicitely go and delimit the grammar:
dlm = qi::lit(','); // as an example, delimit by single comma
rule = timestamp > dlm > cid > dlm > double_;
This is tedious. Something that might work about nicely for you (depending on the amount of input validation that should be performed:
dlm = qi::lit(','); // as an example, delimit by single comma
rule = (timestamp | cid | double_) % dlm;
(This would result in a vector of variant<timestampt_t, cid_t, double>)
Roll your own
You could roll your own parser directive, similar to karma::delimit, but for input.
The idea is outlined in this documentation article by Hartmut Kaiser:
Creating Your Own Generator Component for Spirit.Karma
If you're interested, I could see whether I could make this work as an example (I've not used this before). To be honest, I'm surprised something like this doesn't yet exist, and I think it would be a prime candidate for the Spirit Repository
Here's the solution I'm finally satisfied with. It's based on these three answers:
https://stackoverflow.com/a/12679189/396583
https://stackoverflow.com/a/6069950/396583
https://stackoverflow.com/a/3744742/396583
I've decided not to make it accept arbitrary binary functors though, since I doubt it would have any real-world purpose in context of parsing. So,
#include <boost/proto/deep_copy.hpp>
template <typename D>
struct prefixer
{
template<typename... T>
struct TypeOfPrefixedExpr;
template<typename T>
struct TypeOfPrefixedExpr<T>
{
typedef typename boost::proto::result_of::deep_copy
< decltype ( std::declval<D>() > std::declval<T>() ) >::type type;
};
template<typename T, typename... P>
struct TypeOfPrefixedExpr<T, P...>
{
typedef typename boost::proto::result_of::deep_copy
< decltype ( std::declval<D>() > std::declval<T>()
> std::declval<typename TypeOfPrefixedExpr<P...>::type>() ) >::type type;
};
D dlm_;
prefixer ( D && dlm ) : dlm_ ( dlm ) {}
template <typename U>
typename TypeOfPrefixedExpr<U>::type operator() (U && parser )
{
return boost::proto::deep_copy ( dlm_ > parser );
}
template <typename U, typename ... Tail>
typename TypeOfPrefixedExpr<U, Tail...>::type
operator() (U && parser, Tail && ... tail )
{
return boost::proto::deep_copy ( dlm_ > parser > (*this)(tail ...) );
}
};
template <typename D>
prefixer<D> make_prefixer ( D && dlm )
{
return prefixer<D> ( std::forward<D>(dlm) );
}
And it's used like this:
auto params = make_prefixer(qi::lit(dlm));
cmd_ID = params(string) [ _val = lazy_shared<dc::Auth> (_1) ];
cmd_NAV = params(timestamp, double_, double_, double_, double_, double_)
[
_val = lazy_shared<dc::Navigation>( _1, _2, _3, _4, _5, _6 )
];
cmd_BC = params(timestamp, cid, double_)
[
_val = lazy_shared<dc::BoardControl>(_1, _2, _3)
];
Related
Is it possible to extend all(?) existing C++ JSON libraries with XPath/XPointer or subset with just one C++ implementation? At least those with iterators for object and array values?
I have reviewed three C++ JSON libraries (reviewing nlohmann, Boost.JSON and RapidJSON) to see the internals and check their search functionality. Some have implemented Json pointer. Json pointer is basic, almost like working with json as a name-value list.
XML has XPath and XPointer searches and rules are standardized. With XPath and XPointer you can do more.
One reason to reviewing these libraries was to see if it is possible to extend any of them with better search functionality. Or might it be possible to extend all(?) C++ JSON libraries at once?
A longer text describing this can be found here, trying to be brief.
I tried to do one traverse method that selects json values with one specific property name and that method should work an all tested JSON libraries. If I got that to work it may be possible to add more search logic and get it to work on almost all C++ JSON.
I got this C++ templated function to work an all tested json libraries. It can walk the JSON tree and select json values on all tested libraries.
What is needed to is to implement specializations of is_object, is_array, compare_name, get_value, begin and end. That are just one liners so it's easy.
template<typename json_value>
bool is_object( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_object is allowed"); }
template<typename json_value>
bool is_array( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_array is allowed"); }
template<typename iterator>
bool compare_name( iterator it, std::string_view stringName )
{ static_assert(sizeof(it) == 0, "Only specializations of compare_name is allowed"); }
template<typename iterator, typename json_value>
const json_value* get_value( iterator it )
{ static_assert(sizeof(it) == 0, "Only specializations of get_value is allowed"); }
template<typename iterator, typename json_value>
iterator begin( const json_value& v ) { return std::begin( v ); }
template<typename iterator, typename json_value>
iterator end( const json_value& v ) { return std::end( v ); }
// ------------------------------------------------
// Selects all json values that match property name
template<typename json_value, typename object_iterator,typename array_iterator = object_iterator>
uint32_t select( const json_value& jsonValue, std::string_view stringQuery, std::vector<const json_value*>* pvectorValue = nullptr )
{ assert( is_object( &jsonValue ) || is_array( &jsonValue ) );
uint32_t uCount = 0;
if( is_object( &jsonValue ) == true ) // found object ?
{
for( auto it = begin<object_iterator,json_value>( jsonValue ); it != end<object_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<object_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<object_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
else if( compare_name<object_iterator>( it, stringQuery ) == true )
{ // property name matches, store value if pointer to vector
if( pvectorValue != nullptr ) pvectorValue->push_back( get_value<object_iterator,json_value>( it ) );
uCount++;
}
}
}
else if( is_array( &jsonValue ) == true ) // found array
{
for( auto it = begin<array_iterator,json_value>( jsonValue ); it != end<array_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<array_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<array_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
}
}
return uCount;
}
if this works and if I haven't forgot something, shouldn't it be possible to extend all libraries with just one implementation? The additional logic for XPath and XPointer is not dependent on the implementation of these C++ JSON libraries.
Am I missing something
I'm wondering if there's a way to write a C++ template with different return types.
My use case is a method returning the largest values from a list.
But since I'm using the Qt framework, this function shall be able to deal with numeric and QString values. When feeding this function with a list of QString, the function shall return the length of the largest string. In case of passing numeric values, the input type shall be the return type.
What I've written is this:
template< class T >
auto getMax( QList< T > aList ) -> decltype( std::is_arithmetic< T >::value ? T : int( 0 ) )
{
if ( std::is_arithmetic< T >::value )
{
T Result( aList.isEmpty() ? 0 : aList.first() );
for ( auto lElement : aList )
{
Result = std::max( Result, lElement );
}
return Result;
}
if ( std::is_same< T, QString >::value )
{
// List contains QString -> return length of largest string
int Result( aList.isEmpty() ? 0 : aList.first().length() );
for ( const QString & lrcsElement : aList )
{
Result = std::max( lrcsElement.length(), Result );
}
return Result;
}
return 0;
}
This code compiles with VS 2017.
But when I want to use the template function like this
const QString sError ( tr( "Error" ) );
const QString sWarning( tr( "Warning" ) );
const QString sInfo ( tr( "Information" ) );
const QString sDebug ( tr( "Debug " ) );
auto iMaxTextLength( SMUtils::getMax< QString >( { sError, sWarning, sInfo, sDebug } ) );
the compiler gives me some error messages:
Error C2672: "SMUtils::getMax": no matching overloaded function found.
Error C2893: Failed to specialize function template "unknown-type SMUtils::getMax(QList)".
Error C2119: "li32MaxTextLength": the type for "auto" cannot be deduced from an empty initializer.
Of course I could write a specialized getMax( QStringList ) method, but I was wondering if it's possible to use only one template function.
Is that even possible and if so, how?
Thanks,
Sören
-> decltype( std::is_arithmetic< T >::value ? T : int( 0 ) )
should be
-> std::conditional_t<std::is_arithmetic<T>::value, T, int>;
or even omit it completely and let compiler deduce it (but requires correct return types, so following if constexpr).
and your
if ( std::is_arithmetic< T >::value )
should be
if constexpr ( std::is_arithmetic< T >::value )
I am trying to use boost::bimap for one of my requirements. Below is sample code
typedef bimap<
multiset_of< string >,
multiset_of< string >,
set_of_relation<>
> bm_type;
bm_type bm;
assign::insert( bm )
( "John" , string("lazarus" ) )
( "Peter", string("vinicius") )
( "Peter", string("test") )
( "Simon", string("vinicius") )
( "John", string("viniciusa") )
( "John", string("vinicius") )
I would like to do something as finding matching values for John & Peter, in other words intersection between values for John & Peter for ex: In this case it will be ("vinicius"). Can someone provide some limelight over it?
Here's what I came up with initially:
template <typename Value = std::string, typename Bimap, typename Key>
std::set<Value> projection(Bimap const& bm, Key const& key)
{
std::set<Value> p;
auto range = bm.left.equal_range(key);
auto values = boost::make_iterator_range(range.first, range.second);
for (auto& relation : values)
p.insert(relation.template get<boost::bimaps::member_at::right>());
return p;
}
auto john = projection(bm, "John");
auto peter = projection(bm, "Peter");
std::multiset<std::string> intersection;
std::set_intersection(
john.begin(), john.end(),
peter.begin(), peter.end(),
inserter(intersection, intersection.end())
);
I think it can be more efficient. So I tried replacing the projection on the fly using Boost Range's adaptors:
struct GetRightMember
{
template <typename> struct result { typedef std::string type; };
template <typename T>
std::string operator()(T const& v) const {
return v.template get<boost::bimaps::member_at::right>();
}
};
const GetRightMember getright;
std::cout << "Intersection: ";
// WARNING: broken: ranges not sorted
boost::set_intersection(
bm.left.equal_range("John") | transformed(getright),
bm.left.equal_range("Peter") | transformed(getright),
std::ostream_iterator<std::string>(std::cout, " "));
Sadly it doesn't work - presumably because the transformed ranges aren't sorted.
So I'd stick with the more verbose version (or reconsider my data structure choices). See it Live On Coliru
I'm implementing a multi-dimensional tensor for a linear algebra library in D and this is basically what I was aiming to for the base class:
class Tensor( T_scalar, T_dimensions ..., int T_storageOrder = StorageOrder.columnMajor )
{
}
In the idea, the user can define the characteristics of the tensor through template parameters and as a result I can deduce as many things as possible during compile-time, a bit like Eigen does.
Unfortunately the compiler is not so happy with that definition and triggers an error such as:
Tensor(T_scalar,T_args...,int T_storageOrder = StorageOrder.columnMajor) template tuple parameter must be last one
I'm not so sure why this restriction is in place but I ended up doing what I consider being a hack... basically, having defined the StorageOrder as an enum allows me to check if the last argument of the template tuple parameter matches one of the values from the enum, and if so I can use it to set the value of the StorageOrder for that tensor, otherwise I set it up with a default value.
enum StorageOrder : int
{
columnMajor = -1,
rowMajor = -2
}
class Tensor( T_scalar, T_args ... )
{
private:
alias TensorTraits!( T_scalar, T_args ) traits;
alias traits.dimensions T_dimensions;
alias traits.storageOrder T_storageOrder;
}
struct TensorTraits( T_scalar, T_args ... )
if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
static immutable auto dimensions = mixin( extractDataFromTemplateTupleParameter.dimensions );
static immutable int storageOrder = extractDataFromTemplateTupleParameter.storageOrder;
private:
static auto extractDataFromTemplateTupleParameter()
{
Tuple!( string, "dimensions", int, "storageOrder" ) templateTupleParameterData;
static if ( T_args[$ - 1] == StorageOrder.columnMajor || T_args[$ - 1] == StorageOrder.rowMajor )
{
alias TypeTuple!( T_args[0 .. $ - 1] ) dimensionsTuple;
templateTupleParameterData.storageOrder = T_args[$ - 1];
}
else
{
alias TypeTuple!( T_args ) dimensionsTuple;
templateTupleParameterData.storageOrder = StorageOrder.columnMajor;
}
static assert( dimensionsTuple.length > 0,
"No dimensions have been defined." );
foreach ( dimension; dimensionsTuple )
{
static assert( isIntegral!( typeof( dimension ) ),
"Dimensions sizes needs to be defined as integrals." );
static assert( dimension >= 0,
"Dimensions sizes cannot be negative." );
}
templateTupleParameterData.dimensions = dimensionsTuple.stringof;
return templateTupleParameterData;
}
}
static bool areTemplateParametersValid( T_scalar, T_args ... )()
{
static assert( isNumeric!( T_scalar ),
"The 'T_scalar' template argument is not a numeric type." );
static assert( T_args.length > 0,
"No dimensions have been defined." );
return true;
}
Since I've just started with D, and since I'm not so sure about this hack, I would like to know if this sounds good to you guys or if there's maybe a better way of handling this?
Like you say, it's a hack, and you should avoid hacks where unnecessary.
One (obvious) solution is to move the storage order before the dimensions, although I'm guessing you want to use that default parameter.
To work around that, you could create have specific templates for row and column major:
// Generic Tensor with storage order before dimensions.
class Tensor( T_scalar, int T_storageOrder, T_dimensions... )
{
}
template TensorRowOrder( T_scalar, T_dimensions... )
{
alias Tensor( T_scalar, StorageOrder.rowMajor, T_dimensions ) TensorRowOrder;
}
template TensorColumnOrder( T_scalar, T_dimensions... )
{
alias Tensor( T_scalar, StorageOrder.columnMajor, T_dimensions ) TensorColumnOrder;
}
You can then use TensorRowOrder or TensorColumnOrder in user code, or just Tensor when you need the generic T_storageOrder.
FYI this is what I ended up doing.
class Array( T_scalar, T_args ... )
{
private:
alias ArrayTraits!( T_scalar, T_args ) traits;
alias traits.isDynamic T_isDynamic;
alias traits.shapeAtCompileTime T_shapeAtCompileTime;
alias traits.sizeAtCompileTime T_sizeAtCompileTime;
alias traits.storageOrder T_storageOrder;
alias traits.dataType T_dataType;
}
struct ArrayTraits( T_scalar, T_args ... )
if ( areTemplateParametersValid!( T_scalar, T_args )() )
{
private:
static if ( hasFlag( Flags.storageOrder ) )
alias T_args[0 .. $ - 1] shapeTuple;
else
alias T_args shapeTuple;
public:
static immutable bool isDynamic = hasFlag( Flags.dynamic ) ? true : false;
static immutable auto shapeAtCompileTime = getShapeAtCompileTime();
static immutable size_t sizeAtCompileTime = getSizeAtCompileTime();
static immutable StorageOrder storageOrder = hasFlag( Flags.storageOrder ) ?
T_args[$ - 1] : defaultStorageOrder;
static if ( hasFlag( Flags.dynamic ) == true )
alias T_scalar[] dataType;
else
alias T_scalar[sizeAtCompileTime] dataType;
public:
static auto getShapeAtCompileTime()
{
static if ( hasFlag( Flags.dynamic ) == true )
{
static assert( shapeTuple.length == 1,
"The shape of a dynamic array needs to be defined at run-time." );
size_t[1] shapeAtCompileTime = [Storage.dynamic];
return shapeAtCompileTime;
}
else
{
static assert( shapeTuple.length > 0,
"No dimensions have been defined." );
size_t[shapeTuple.length] shapeAtCompileTime;
foreach ( i, dimension; shapeTuple )
{
static assert( isIntegral!( typeof( dimension ) ),
"Dimensions sizes for a static array needs to be defined as integrals." );
static assert( dimension > 0,
"Dimensions sizes for a static array cannot be null or negative." );
shapeAtCompileTime[i] = dimension;
}
return shapeAtCompileTime;
}
}
static size_t getSizeAtCompileTime()
{
if ( hasFlag( Flags.dynamic ) == true )
return 0;
size_t size = 1;
foreach ( dimension; shapeAtCompileTime )
size *= dimension;
return size;
}
private:
/++ Parses the template tuple parameter to extract the different flags passed, if any. +/
static int getFlags()
{
int flags = 0;
if ( is( typeof( T_args[0] ) == Storage ) && T_args[0] == Storage.dynamic )
flags |= Flags.dynamic;
if ( is( typeof( T_args[$ - 1] ) == StorageOrder ) )
flags |= Flags.storageOrder;
return flags;
}
/++ Checks if the template tuple parameter contains a specific flag. +/
static bool hasFlag( Flags flag )
{
return (getFlags() & flag) == 0 ? false : true;
}
private:
enum Flags : int
{
dynamic = 1 << 0,
storageOrder = 1 << 1
}
}
bool areTemplateParametersValid( T_scalar, T_args ... )()
{
static assert( T_args.length > 0,
"No dimensions have been defined." );
return true;
}
First of all, sorry for the inaccurate title, it's just that I don't actually know whats causing the compilation error ( Im new to spirit/phoenix/tuple ), hence for readability of my question I exported the entire grammar to pastebin:
http://pastebin.com/RsGM8E4r
The code is compiled in Visual Studio 2010 with:
Iterator = std::string::const_iterator
and other information you need to understand the grammar and my question at the bottom:
namespace parser { namespace container1 {
template < typename _C >
class atom : public element < _C >
{
private:
typedef typename std::basic_string < _C > _string;
public:
explicit atom ( const boost::variant < bool, long, double, _string > & value )
: _value ( value )
{
_element_type = TY_ATOM;
}
explicit atom ()
{
}
template < typename T >
const T as () const
{
return boost::apply_visitor ( atom_visitor < _C, T > (), _value );
}
private:
boost::variant < bool, long, double, _string > _value;
};
template < typename _C >
struct item
{
typedef typename element < _C > type;
typedef typename boost::shared_ptr < type > ptr;
};
}}
group and list also have element as base.
Now, the thing I don't understand is, when you look at the grammar, the rule definition for atom is:
atom =
( qi::double_ | qi::long_ | qi::bool_ | string ) [ qi::_val = phoenix::construct < _item_ptr > ( phoenix::new_ < _atom > ( qi::_1 ) ) ]
;
This gives a very long list of compiler error which I can't really comprehend .. exported to pastebin again: http://pastebin.com/k4HseJ01
If I however change the rule to
atom =
( qi::double_ | qi::long_ | qi::bool_ | string ) [ qi::_val = phoenix::construct < _item_ptr > ( phoenix::new_ < _atom > () ) ]
;
it compiles successfully, but well I need to get the parsed data from that rule :P
Thank you very much in advance for any help, I'm really stuck at that for days.