2

I'm trying to build s-expression objects using boost::proto with the following terminals:

        typedef proto::terminal< const char* >::type string_term_t;
        typedef proto::terminal< uint32_t >::type uint32_term_t;
        typedef proto::terminal< float >::type float_term_t;

and using it like:

void testInit()
{
    auto v = string_term_t("foo") , string_term_t("bla") , (float_term_t(5.6), string_term_t("some"));
    proto::display_expr(v);
}

However this does not compile for me;

Test.cpp:18:33: error: no matching function for call to ‘boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<const char*>, 0l>::expr(const char [4])’
boost_1_46_0/boost/proto/proto_fwd.hpp:300:16: note: candidates are: boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<const char*>, 0l>::expr()
boost_1_46_0/boost/proto/proto_fwd.hpp:300:16: note:                 boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<const char*>, 0l>::expr(const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<const char*>, 0l>&)
Test.cpp:18:33: error: unable to deduce ‘auto’ from ‘<expression error>’
Test.cpp:18:73: error: expected ‘)’ before ‘(’ token

what i'm doing wrong? any suggestions how to obtain something similar or equivalent to s-expressions using boost::proto ?

lurscher
  • 25,930
  • 29
  • 122
  • 185

3 Answers3

5

The proto::expr<> type does not define constructors; hence, your problem. Try defining your types like this instead:

typedef proto::literal< const char* > string_term_t;
typedef proto::literal< uint32_t > uint32_term_t;
typedef proto::literal< float > float_term_t;
Eric Niebler
  • 5,927
  • 2
  • 29
  • 43
  • 6
    I will also say that creating an expression template and assigning to an ``auto`` variable like you're doing is never safe. Proto expression trees hold internal nodes by reference. If those nodes are temporary objects as you have them, those nodes get deleted at the end of the full expression (the semicolon), which results in dangling references. You can use `proto::deep_copy` to make sure everything is stored by value before assigning the expression tree to a local variable. HTH! – Eric Niebler Apr 07 '12 at 21:08
1

I suspect there's something inerently wrong in the way you are using it; I've just started reading this, so I am totally newbie; though, the following compiles and does something

#include <boost/proto/proto.hpp>

using namespace boost;

typedef proto::terminal< const char* >::type string_term_t;

void testInit()
{
  auto v = string_term_t ({"foo"});
  proto::display_expr(v);
}

int main()
{
  testInit();
  return 0;
}

In particular I find suspect the usage of the "bare" commas in the definition of v; I don't know if it is expected to be a new feature of C++11 or boost magic, but I won't expect it to work at least as is.

ADD

After a little bit of playing, we ended with discovering that the comma operator is an operator iff enclosed inside ( ) and it is not when "bare". The following worked

typedef proto::terminal< const char* >::type string_term_t;
typedef proto::terminal< uint32_t >::type uint32_term_t;
typedef proto::terminal< float >::type float_term_t;

void testInit()
{
  auto v = (string_term_t({"foo"}) , string_term_t({"bla"}) , (float_term_t({5.6}), string_term_t({"some"})));
  proto::display_expr(v);
}

(written for the future readers; the () enclosing { "foo" } or whatver can be removed).

ShinTakezou
  • 9,432
  • 1
  • 29
  • 39
  • 1
    no, the comma is a iso 2003 c++ operator, and proto is supposed to overload all the operators – lurscher Apr 07 '12 at 17:36
  • i'll try the initializer with the {} – lurscher Apr 07 '12 at 17:36
  • @lurscher thanks. I had to imagine that like every other operator it can be overloaded. Though, this information doesn't help yet. And, is it really recognized as operator when bare? By bare I mean not enclosed inside `( )` – ShinTakezou Apr 07 '12 at 17:41
  • yeah it seems to be related with the commas; i tried replacing other operators | - + and it works – lurscher Apr 07 '12 at 17:43
  • 1
    The brackets are needed due to the syntax for multiple variable declaration: contrast `int i = 0, j = 1;` with `int j; int i = (0, j = 1);`. – Luc Danton Apr 07 '12 at 18:24
0

I turned out doing a compile-time S-expression without relying on boost. The only issue is that relies on c++11


sexpr.h

#ifndef S_EXPRESSION_H
#define S_EXPRESSION_H

#include <algorithm>

template< typename... Subexprs > class SExpr;

template< typename SExprType, unsigned int Idx > class SExprGetter;

template< typename SExprType >
class SExprGetter< SExprType, 0 >
{
    SExprType* tree;
public:
    typedef typename SExprType::Expr_0_type return_type;

    SExprGetter(SExprType& _v) : tree(& _v) {}
    SExprGetter(SExprGetter&& _o) : tree(_o.tree) {}

    return_type& getValue() { return tree->get_storage(); }

    template< unsigned int Idx>
    SExprGetter< return_type , Idx > getChild()
    {
        return getValue().template getChild<Idx>();
    }

    static constexpr unsigned int childs()
    {
         return return_type::childs();
    }
};

template< typename SExprType >
class SExprGetter< SExprType, 1 >
{
    SExprType* tree;
    typedef typename SExprType::Remainder_type remainder_type_1;
public:
    typedef typename remainder_type_1::Expr_0_type return_type;

    SExprGetter(SExprType& _v) : tree(& _v) {}
    SExprGetter(SExprGetter&& _o) : tree(_o.tree) {}

    return_type& getValue() { return tree->get_remainder_storage().get_storage(); }

    template< unsigned int Idx>
    SExprGetter< return_type , Idx > getChild()
    {
        return getValue().template getChild<Idx>();
    }

    static constexpr unsigned int childs()
    {
         return return_type::childs();
    }
};

template< typename SExprType >
class SExprGetter< SExprType, 2 >
{
    SExprType* tree;
    typedef typename SExprType::Remainder_type remainder_type_1;
    typedef typename remainder_type_1::Remainder_type remainder_type_2;
public:
    typedef typename remainder_type_2::Expr_0_type return_type;

    SExprGetter(SExprType& _v) : tree(& _v) {}
    SExprGetter(SExprGetter&& _o) : tree(_o.tree) {}

    return_type& getValue() { return tree->get_remainder_storage().get_remainder_storage().get_storage(); }

    template< unsigned int Idx>
    SExprGetter< return_type , Idx > getChild()
    {
        return getValue().template getChild<Idx>();
    }

    static constexpr unsigned int childs()
    {
         return return_type::childs();
    }
};

template< typename SExprType >
class SExprGetter< SExprType, 3 >
{
    SExprType* tree;
    typedef typename SExprType::Remainder_type remainder_type_1;
    typedef typename remainder_type_1::Remainder_type remainder_type_2;
    typedef typename remainder_type_2::Remainder_type remainder_type_3;
public:
    typedef typename remainder_type_3::Expr_0_type return_type;

    SExprGetter(SExprType& _v) : tree(& _v) {}
    SExprGetter(SExprGetter&& _o) : tree(_o.tree) {}

    return_type& getValue() { return tree->get_remainder_storage().get_remainder_storage().get_remainder_storage().get_storage(); }

    template< unsigned int Idx>
    SExprGetter< return_type , Idx > getChild()
    {
        return getValue().template getChild<Idx>();
    }

    static constexpr unsigned int childs()
    {
         return return_type::childs();
    }
};


template< typename T0, typename... Subexprs >
class SExpr< T0, Subexprs... >
{
    T0 _t0_storage;
    SExpr< Subexprs... > _remainder_storage;

public:

    typedef T0 Expr_0_type;
    typedef SExpr< Subexprs... > Remainder_type;

    SExpr(T0 _t, Subexprs... sexprs) : _t0_storage(_t), _remainder_storage(sexprs...) {}
    SExpr(T0&& _t, Subexprs && ... sexprs) : _t0_storage(_t), _remainder_storage(sexprs...) {}


    T0& get_storage() { return _t0_storage; }
    Remainder_type& get_remainder_storage() { return _remainder_storage; }

    template< unsigned int Idx>
    SExprGetter< SExpr , Idx > getChild()
    {
        SExprGetter< SExpr, Idx > getter(*this);
        return getter;
    }

    static constexpr unsigned int childs()
    {
         return sizeof...(Subexprs) + 1;
    }
};


template< typename T0>
class SExpr< T0 >
{
    T0 _t0_storage;

    public:

    typedef T0 Expr_0_type;
    typedef void Remainder_type;

    SExpr(T0 _t) : _t0_storage(_t) {}
    SExpr(T0&& _t) : _t0_storage(_t) {}

    T0& get_storage() { return _t0_storage; }

    static constexpr unsigned int childs()
    {
         return 1;
    }

    template< unsigned int Idx>
    SExprGetter< SExpr , Idx > getChild()
    {
        SExprGetter< SExpr, Idx > getter(*this);
        return getter;
    }
};


template <typename... Exprs>
SExpr<Exprs...> _S_expr(Exprs... exprs) {
    return
    {
        exprs...
    };
};

#endif  /* S_EXPRESSION_H */

test.cpp

#include <iostream>
#include "sexpr.h"
#include <string>

using namespace std;

int main()
{
    auto s_expr_1 = _S_expr(3);
    auto s_expr_2 = _S_expr(3, std::string("foo"));
    auto s_expr_3 = _S_expr(3, _S_expr(3, "bar"), std::string("foo"));

    auto ff_1 = s_expr_1.getChild<0>().getValue();
    cout << " ff_1: " << ff_1 << endl;

    auto ff_2 = s_expr_2.getChild<1>().getValue();
    cout << " ff_2: " << ff_2 << endl;

    auto ff_3 = s_expr_3.getChild<1>().getChild<1>().getValue();
    cout << " ff_3: " << ff_3 << endl;

    cout << " s expr 3 has " << s_expr_3.childs() << " and the first leaf has " << s_expr_3.getChild< s_expr_3.childs() - 2 >().childs() << endl;
};
lurscher
  • 25,930
  • 29
  • 122
  • 185