So I've figured out the problem. Basically, I was doing something like this: --------------------- struct SmartContext { template<typename Expr, typename Enabler = void> struct eval; template<typename Expr> struct eval<Expr, /* something here to catch arity == 0 */> { /* implementation for terminals */ }; template<typename Expr> struct eval<Expr, /* something here that looks at the children of Expr */> { /* one implementation for non-terminals */ }; template<typename Expr> struct eval<Expr, /* something else here that looks at the children of Expr */> { /* 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<Expr, 0> { static_assert(proto::arity_of<Expr> == 0, "Accessing the value of a non-terminal."); }; }} --------------------- Sebastian