How can I use the "new" operator in a boost::xpressive semantic action?

263 Views Asked by At

It seems that boost::xpressive doesn't provide a lazily evaluated version of the new operator, so this semantic action won't compile:

using namespace boost::xpressive ;
std::vector<int*> vec ;

// Match any integer and capture into s1.
// Then use a semantic action to push it onto vec.
sregex num = (s1= +digit)[ ref(vec)->*push_back( new as<int>(s1) ) ] ;

Is there a construct for using the new operator in semantic actions? For example, boost::phoenix provides the new_ function for lambdas. Does xpressive provide something similar for semantic actions?

1

There are 1 best solutions below

0
On

This is the best I've come up with so far. This code defines a function that allows you to use the syntax new_<T>::with(...) as the semantic action equivalent to new T(...). The function is modeled after the lazy function example in the boost xpressive user guide. (The snippet below only supports constructors with up to 2 parameters, but adding more is a matter of copy/paste.)

using namespace boost::xpressive ;

template <typename _ObjectType>
struct new_impl
{
    typedef _ObjectType* result_type;

    _ObjectType* operator()() const
    {
        return new _ObjectType() ;
    }

    template<typename _T0>
    _ObjectType* operator()(_T0 const &a0) const
    {
        return new _ObjectType( a0 ) ;
    }

    template<typename _T0, typename _T1>
    _ObjectType* operator()(_T0 const &a0, _T1 const &a1) const
    {
        return new _ObjectType( a0, a1 ) ;
    }
};

template <typename _ObjectType>
struct new_
{
    static const typename function<new_impl<_ObjectType> >::type with ;
};
template <typename _ObjectType>
const typename function<new_impl<_ObjectType> >::type new_<_ObjectType>::with = {{}};

And here it is in action:

int main()
{
    std::vector<int*> vec ;

    // Matches an integer, with a semantic action to push it onto vec
    sregex num = (s1= +digit)
                 [ ref(vec)->*push_back( new_<int>::with( as<int>(s1) ) ) ] ;

    // Space-delimited list of nums
    sregex num_list = num >> *(' ' >> num) ;

    std::string str = "8 9 10 11" ;
    if ( regex_match( str, num_list ) )
    {
        std::cout << "Found an int list: " ;
        BOOST_FOREACH( int* p, vec )
        {
            std::cout << *p << ' ' ;
        }
    }
    else
    {
        std::cout << "Didn't find an int list." ;
    }

    return 0 ;
}

Output:

Found an int list: 8 9 10 11

To improve the generality of the code above, it may be better to change the parameter types to use boost::add_reference<> and boost::add_const<>, but you get the idea.