boost::proto user guide - compile error creating a lazy function

::type
Hi, I am going through proto user guide. I am getting compiling error for the following piece code (it's pretty much copy and pasted from the guide). I used 1.40 and gcc. #include <iostream> #include <boost/mpl/int.hpp> #include <boost/proto/core.hpp> #include <boost/proto/context.hpp> #include <boost/proto/debug.hpp> #include <cmath> #include <vector> namespace proto = boost::proto; template<int I> struct placeholder {}; // Define some placeholders proto::terminal< placeholder< 1 > >::type const _1 = {{}}; proto::terminal< placeholder< 2 > >::type const _2 = {{}}; struct calculator_context : proto::callable_context< calculator_context const > { // Values to replace the placeholders std::vector<double> args; // Define the result type of the calculator. // (This makes the calculator_context "callable".) typedef double result_type; // Handle the placeholders: template<int I> double operator()(proto::tag::terminal, placeholder) const { return this->args[I]; } }; // Define a pow_fun function object template<int Exp> struct pow_fun { typedef double result_type; double operator()(double d) const { return std::pow(d, Exp); } }; // Define a lazy pow() function for the calculator DSEL. // Can be used as: pow< 2 >(_1) template<int Exp, typename Arg> typename proto::function< typename proto::terminal<pow_fun<Exp> >::type , Arg const & pow1(Arg const &arg) { typedef typename proto::function< typename proto::terminal<pow_fun<Exp> >::type , Arg const & >::type result_type; result_type result = {{{}}, arg}; return result; } int main() { calculator_context ctx; ctx.args.push_back(3); std::cout << boost::proto::eval( pow1<2>( _1 ), ctx ); return 0; } The error says: calc2.cpp: In function 'int main()': calc2.cpp:116: error: no matching function for call to 'eval(boost::proto::exprns_::expr<boost::proto::tag::function, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<pow_fun<2> >, 0l>, const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<placeholder<1> >, 0l>&>, 2l>, calculator_context&)' /auto/cigprod/spg/lx86_64/opt/boost_1_40_0/boost/proto/eval.hpp:91: note: candidates are: typename boost::proto::result_of::eval<Expr, Context>::type boost::proto::eval(Expr&, Context&) [with Expr = boost::proto::exprns_::expr<boost::proto::tag::function, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<pow_fun<2> >, 0l>, const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<placeholder<1> >, 0l>&>, 2l>, Context = calculator_context] /auto/cigprod/spg/lx86_64/opt/boost_1_40_0/boost/proto/eval.hpp:100: note: typename boost::proto::result_of::eval<Expr, Context>::type boost::proto::eval(Expr&, const Context&) [with Expr = boost::proto::exprns_::expr<boost::proto::tag::function, boost::proto::argsns_::list2<boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<pow_fun<2> >, 0l>, const boost::proto::exprns_::expr<boost::proto::tag::terminal, boost::proto::argsns_::term<placeholder<1> >, 0l>&>, 2l>, Context = calculator_context] Thanks. -- View this message in context: http://www.nabble.com/boost%3A%3Aproto-user-guide---compile-error-creating-a... Sent from the Boost - Users mailing list archive at Nabble.com.

Hi Tom, comments inline ... Tom Babbin wrote:
Hi,
I am going through proto user guide. I am getting compiling error for the following piece code (it's pretty much copy and pasted from the guide). I used 1.40 and gcc.
#include <iostream> #include <boost/mpl/int.hpp> #include <boost/proto/core.hpp> #include <boost/proto/context.hpp> #include <boost/proto/debug.hpp> #include <cmath> #include <vector>
namespace proto = boost::proto;
template<int I> struct placeholder {};
// Define some placeholders proto::terminal< placeholder< 1 > >::type const _1 = {{}}; proto::terminal< placeholder< 2 > >::type const _2 = {{}};
struct calculator_context : proto::callable_context< calculator_context const > { // Values to replace the placeholders std::vector<double> args;
// Define the result type of the calculator. // (This makes the calculator_context "callable".) typedef double result_type;
// Handle the placeholders: template<int I> double operator()(proto::tag::terminal, placeholder) const
Should be placeholder<I> here ----------------^^^^^^^^^^^
{ return this->args[I]; } };
// Define a pow_fun function object template<int Exp> struct pow_fun { typedef double result_type; double operator()(double d) const { return std::pow(d, Exp); } };
// Define a lazy pow() function for the calculator DSEL. // Can be used as: pow< 2 >(_1) template<int Exp, typename Arg> typename proto::function< typename proto::terminal<pow_fun<Exp> >::type , Arg const &
::type
Return type needs a const.
pow1(Arg const &arg) { typedef typename proto::function< typename proto::terminal<pow_fun<Exp> >::type , Arg const & >::type result_type;
result_type result = {{{}}, arg}; return result; }
int main() { calculator_context ctx; ctx.args.push_back(3);
std::cout << boost::proto::eval( pow1<2>( _1 ), ctx );
The problem is that proto::eval() takes its first argument by non-const reference. The temporary expression returned by pow1 doesn't bind to it as it's defined in the users' guide. Adding a const-qualification to the return type solves the problem. I'll update the docs for 1.41. Thanks for the report. -- Eric Niebler BoostPro Computing http://www.boostpro.com

The problem is that proto::eval() takes its first argument by non-const reference. The temporary expression returned by pow1 doesn't bind to it as it's defined in the users' guide. Adding a const-qualification to the return type solves the problem.
I'll update the docs for 1.41. Thanks for the report.
Hi, Eric, Thanks for the quick response. Adding a const does fix the problem. However, I am relatively new to meta programming. How come a const expression binds to the first argument of eval, while a non-const does not? Thanks again.

Tom Babbin wrote:
The problem is that proto::eval() takes its first argument by non-const reference. The temporary expression returned by pow1 doesn't bind to it as it's defined in the users' guide. Adding a const-qualification to the return type solves the problem.
I'll update the docs for 1.41. Thanks for the report.
Hi, Eric,
Thanks for the quick response. Adding a const does fix the problem. However, I am relatively new to meta programming. How come a const expression binds to the first argument of eval, while a non-const does not?
Consider this: template<class T> void foo(T &) {} struct S {}; S rvalue() { return S(); } S const const_rvalue() { return S(); } Now the following invocation fails: foo( rvalue() ); // error, non-const rvalue cannot // bind to an lvalue reference But the following invocation succeeds: foo( const_rvalue() ); // OK The reason is because in the second invocation, the template argument T is deduced to be "B const", and an rvalue can bind to a const lvalue reference. In the first invocation, T is deduced to "B" and an rvalue cannot bind to a non-const lvalue reference. HTH, -- Eric Niebler BoostPro Computing http://www.boostpro.com

Eric Niebler <eric <at> boostpro.com> writes:
The reason is because in the second invocation, the template argument T is deduced to be "B const", and an rvalue can bind to a const lvalue reference. In the first invocation, T is deduced to "B" and an rvalue cannot bind to a non-const lvalue reference.
HTH,
Thanks again, Eric. This is really helpful.
participants (2)
-
Eric Niebler
-
Tom Babbin