So I've figured out the problem. Basically, I was doing something like
this:
---------------------
struct SmartContext {
template
struct eval;
template<typename Expr>
struct eval {
/* implementation for terminals */
};
template<typename Expr>
struct eval {
/* one implementation for non-terminals */
};
template<typename Expr>
struct eval {
/* another implementation for non-terminals */
};
};
---------------------
Unfortunately, those specializations are all tested at the same time.
Thus, even for terminal expressions, the stuff looking at the children was
evaluated. However, the "child" of a terminal is the underlying value
implementation, so this stuff tried to access the value implementation as
if it was an expression. Thus the compilation errors.
Is there a particular reason why terminals are implemented this way? Does
it make Proto implementation considerably more convenient? Because if not,
it would be nice to change it so that proto::child() and proto::value() are
not synonyms, but instead simply don't compile for terminals and
non-terminals, respectively. That would have helped a lot in detecting this
error.
Actually, a static_assert would suffice. Something like:
---------------------
namespace proto { namespace result_of {
template <typename Expr>
struct value : proto::result_of::child_n {
static_assert(proto::arity_of<Expr> == 0,
"Accessing the value of a non-terminal.");
};
}}
---------------------
Sebastian