I'd like to build on the Boost Proto "Unpacking Expressions" example from here by using a template parameter to specify the return type of the do_eval
transform (hitherto double
).
For brevity I'll present a working, simplified (plus-only) version of do_eval
:
struct do_eval2 : proto::callable
{
typedef double result_type;
template <typename X, typename Y>
result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};
I then add a template parameter T
instead of double
:
template <typename T>
struct do_eval2 : proto::callable
{
typedef T result_type;
template <typename X, typename Y>
result_type operator()(proto::tag::plus, X x, Y y) const { return x + y; }
};
and modify the associated eval
structure to:
struct eval2
: proto::or_<
proto::when<proto::terminal<proto::_>, proto::_value>
, proto::otherwise<do_eval2<double>(proto::tag_of<proto::_>(),
eval2(proto::pack(proto::_))...)>
>
{};
but when I use it, as shown in the code below, I get errors starting with error: cannot bind ‘std::ostream {aka std::basic_ostream}’ lvalue to ‘std::basic_ostream&&’ How can I satisfy the compiler?
int main(int argc, char *argv[])
{
int one = 1, two = 2;
cout << eval2()(phoenix::ref(one)+phoenix::ref(two)) << '\n';
return 0;
}
As you can see here:
Transforms are typically of the form proto::when< Something, R(A0,A1,...) >. The question is whether R represents a function to call or an object to construct, and the answer determines how proto::when<> evaluates the transform. proto::when<> uses the proto::is_callable<> trait to disambiguate between the two. Proto does its best to guess whether a type is callable or not, but it doesn't always get it right. It's best to know the rules Proto uses, so that you know when you need to be more explicit.
For most types R, proto::is_callable checks for inheritance from proto::callable. However, if the type R is a template specialization, Proto assumes that it is not callable even if the template inherits from proto::callable.
The documentation proposes to solutions: you either wrap every invocation of do_eval<double>
with proto::call
or you simply specialize is_callable
inside the boost::proto namespace and forget about the problem.
namespace boost { namespace proto
{
// Tell Proto that do_eval2<> is callable
template<typename T>
struct is_callable<do_eval2<T> >
: mpl::true_
{};
}}
[Edit:] Here is the proto::call
alternative:
struct eval2
: proto::or_<
proto::when<proto::terminal<proto::_>, proto::_value>
, proto::otherwise<
proto::call<do_eval2<double>(proto::tag_of<proto::_>(),
eval2(proto::pack(proto::_))...)>>
>
{};