Domanda

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;
}
È stato utile?

Soluzione

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::_))...)>>
    >
{};

Altri suggerimenti

See the previous answer. I'd also add that another solution would be to define do_eval2 like this:

template <typename T, typename D = proto::callable>
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; }
};

Note the extra dummy template parameter.

EDIT: Also, in the next version of Proto, currently under development, you won't need to know about this piece of arcana, and things should Just Work. I'll be talking about it at C++Now in a few weeks.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top