[phoenix] [clang] error assigning function object
Hi there, I'm experiencing a compiler error in code that tries to assign a Boost.Phoenix function object returned by invoking a phoenix::function with a std::string as one of the bound parameters. I've reduced my error to the following minimal code: #include <string> #include <boost/phoenix/core/argument.hpp> #include <boost/phoenix/function.hpp> struct S { void operator()(std::string, int) const; }; boost::phoenix::function<S> lazy; auto func1 = lazy(std::string(), boost::phoenix::placeholders::_1); auto func2 = func1; void foo() { func2 = func1; } My compiler version is clang 3.7; the error does not occur with gcc 5.1. The error also goes away if I change the type of the first argument from std::string to a different type (like int). The compiler error is shown below. Any ideas as to what is going on? Am I doing something wrong, or did I run into a bug in Phoenix? Thanks, Nate In file included from test.cpp:81: In file included from /home/nr/dev/dist/boost/include/boost/phoenix/core/argument.hpp:13: In file included from /home/nr/dev/dist/boost/include/boost/phoenix/core/actor.hpp:25: In file included from /home/nr/dev/dist/boost/include/boost/proto/make_expr.hpp:100: In file included from /home/nr/dev/dist/boost/include/boost/proto/detail/make_expr_.hpp:3: /home/nr/dev/dist/boost/include/boost/proto/detail/preprocessed/make_expr_.hpp:73:88: error: no type named 'type' in 'boost::proto::transform<boost::proto::switch_<boost::phoenix::phoenix_generator, boost::proto::tag_of<boost::proto::_> ()>, void>::result<boost::phoenix::phoenix_generator (boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>>, 2>)>' typedef typename proto_generator::template result<proto_generator(expr_type)>::type result_type; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ /home/nr/dev/dist/boost/include/boost/proto/make_expr.hpp:180:34: note: in instantiation of template class 'boost::proto::detail::make_expr_<boost::proto::tagns_::tag::assign, boost::phoenix::phoenix_domain, boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>, void, void, void, void, void, void, void, void, void>' requested here typename detail::make_expr_< ^ /home/nr/dev/dist/boost/include/boost/phoenix/core/actor.hpp:225:36: note: in instantiation of template class 'boost::proto::result_of::make_expr<boost::proto::tagns_::tag::assign, boost::phoenix::phoenix_domain, boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>, void, void, void, void, void, void, void, void, void>' requested here typename proto::result_of::make_expr< ^ /home/nr/dev/dist/boost/include/boost/phoenix/core/actor.hpp:185:12: note: while substituting deduced template arguments into function template 'operator=' [with A0 = const boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>] struct actor ^ /home/nr/dev/dist/boost/include/boost/proto/matches.hpp:830:44: note: in instantiation of template class 'boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>>, 2>' requested here : Cases::template case_<typename Expr::proto_tag>::template impl<Expr, State, Data> ^ /home/nr/dev/dist/boost/include/boost/proto/transform/impl.hpp:238:13: note: in instantiation of template class 'boost::proto::switch_<boost::phoenix::phoenix_generator, boost::proto::tag_of<boost::proto::_> ()>::impl<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>>, 2>, int, boost::proto::envns_::empty_env>' requested here : PrimitiveTransform::template impl<Expr, empty_state, empty_env> ^ /home/nr/dev/dist/boost/include/boost/proto/transform/impl.hpp:255:9: note: in instantiation of template class 'boost::proto::detail::apply_transform<boost::phoenix::phoenix_generator (boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>>, 2>)>' requested here BOOST_PROTO_TRANSFORM_(PrimitiveTransform, X) ^ /home/nr/dev/dist/boost/include/boost/proto/transform/impl.hpp:194:48: note: expanded from macro 'BOOST_PROTO_TRANSFORM_' typedef typename boost::proto::detail::apply_transform<Sig>::result_type type; \ ^ /home/nr/dev/dist/boost/include/boost/proto/detail/preprocessed/make_expr_.hpp:73:43: note: in instantiation of template class 'boost::proto::transform<boost::proto::switch_<boost::phoenix::phoenix_generator, boost::proto::tag_of<boost::proto::_> ()>, void>::result<boost::phoenix::phoenix_generator (boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::assign, boost::proto::argsns_::list2<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>>, 2>)>' requested here typedef typename proto_generator::template result<proto_generator(expr_type)>::type result_type; ^ /home/nr/dev/dist/boost/include/boost/proto/make_expr.hpp:180:34: note: in instantiation of template class 'boost::proto::detail::make_expr_<boost::proto::tagns_::tag::assign, boost::phoenix::phoenix_domain, boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>, void, void, void, void, void, void, void, void, void>' requested here typename detail::make_expr_< ^ /home/nr/dev/dist/boost/include/boost/phoenix/core/actor.hpp:213:36: note: in instantiation of template class 'boost::proto::result_of::make_expr<boost::proto::tagns_::tag::assign, boost::phoenix::phoenix_domain, boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>, void, void, void, void, void, void, void, void, void>' requested here typename proto::result_of::make_expr< ^ test.cpp:96:8: note: while substituting deduced template arguments into function template 'operator=' [with A0 = boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::phoenix::detail::tag::function_eval, boost::proto::argsns_::list3<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<S>, 0>, boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<std::basic_string<char>>, 0>, boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1>>, 0>>>, 3>>] func2 = func1; ^ 1 error generated.
At Fri, 8 Jan 2016 01:29:54 +0000 Nathan Ridge wrote:
Hi there,
I'm experiencing a compiler error in code that tries to assign a Boost.Phoenix function object returned by invoking a phoenix::function with a std::string as one of the bound parameters.
I've reduced my error to the following minimal code:
#include <string> #include <boost/phoenix/core/argument.hpp> #include <boost/phoenix/function.hpp>
struct S { void operator()(std::string, int) const; };
boost::phoenix::function<S> lazy;
auto func1 = lazy(std::string(), boost::phoenix::placeholders::_1); auto func2 = func1;
void foo() { func2 = func1; }
My compiler version is clang 3.7; the error does not occur with gcc 5.1.
The error also goes away if I change the type of the first argument from std::string to a different type (like int).
The compiler error is shown below. Any ideas as to what is going on? Am I doing something wrong, or did I run into a bug in Phoenix?
Thanks, Nate
Every Phoenix actor has three `operator=` functions. One is a normal copy assignment, and the other two are for generating lazy assignment functions (one takes a mutable actor, and the other an immutable one). Gcc is selecting the copy assignment in this instance, and Clang is selecting the lazy assignment function. I believe Gcc is correct in this circumstance, because the copy-assignment function is not templated and therefore should take precedence according to the overload resolution rules. So I _think_ this is a bug in Clang. This came up in boost log over a year ago; Joel and I thought it was a bug in Clang at the time. We should've provided them with a minimal example to see their answer (maybe Joel did?) - I will reduce this further and provide it to them unless you feel the need to. This is unlikely to be an issue with phoenix before C++11 because it requires a named instance of a phoenix actor, and few wanted to write the monstrous type manually. Example: namespace phx = boost::phoenix; int foo; auto lazy_assign = (phx::ref(foo) = phx::placeholders::_1); `lazy_assign` is a phoenix actor, whose `operator()` will take the first argument by const reference and assign it to `foo`. But it is also a phoenix actor like `phoenix::ref`, so: lazy_assign = (phx::placeholders::_2); tries to create new phoenix actor (lazy function), whose semantics are really confusing (and thus an error is likely appropriate). Lee
On Sat, 9 Jan 2016 13:39:33 -0500 Lee Clagett <forum@leeclagett.com> wrote:
namespace phx = boost::phoenix; int foo; auto lazy_assign = (phx::ref(foo) = phx::placeholders::_1);
`lazy_assign` is a phoenix actor, whose `operator()` will take the first argument by const reference and assign it to `foo`. But it is also a phoenix actor like `phoenix::ref`, so:
lazy_assign = (phx::placeholders::_2);
tries to create new phoenix actor (lazy function), whose semantics are really confusing (and thus an error is likely appropriate).
I just realized this is valid code since `operator=` returns a reference to the left-hand-size. Although, its still an odd expression. Lee
Every Phoenix actor has three `operator=` functions. One is a normal copy assignment, and the other two are for generating lazy assignment functions (one takes a mutable actor, and the other an immutable one). Gcc is selecting the copy assignment in this instance, and Clang is selecting the lazy assignment function. I believe Gcc is correct in this circumstance, because the copy-assignment function is not templated and therefore should take precedence according to the overload resolution rules. So I _think_ this is a bug in Clang.
Thanks for the explanation!
This came up in boost log over a year ago; Joel and I thought it was a bug in Clang at the time. We should've provided them with a minimal example to see their answer (maybe Joel did?) - I will reduce this further and provide it to them unless you feel the need to.
Please go ahead - thanks! If you end up filing a clang bug, could you share the bug number here? By the way, to explain _why_ I'm trying to assign the actor: I'm not trying to assign it explicitly, but I'm capturing it by value in a lambda, and this seems to require the assignment operator: #include <string> #include <boost/phoenix/core/argument.hpp> #include <boost/phoenix/function.hpp> struct S { void operator()(std::string, int) const; }; boost::phoenix::function<S> lazy; void foo() { auto func1 = lazy(std::string(), boost::phoenix::placeholders::_1); [func1]{}(); } Thanks, Nate
participants (2)
-
Lee Clagett
-
Nathan Ridge