Boost logo

Boost Users :

Subject: Re: [Boost-users] [phoenix] [clang] error assigning function object
From: Lee Clagett (forum_at_[hidden])
Date: 2016-01-09 13:39:33

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).


Boost-users list run by williamkempf at, kalb at, bjorn.karlsson at, gregod at, wekempf at