1

I was just wondering and write the following code: (I am not asking for work arounds, I just want to know whether bind() handles this perfectly or not). Besides, I think bind can handle this and define an order for it, but I am not sure or maybe it is just a parameter evaluation order issue.

#include <functional>
#include <utility>
#include <iostream>
using namespace std;
class increment{
public : 
    string operator()(int& x)
    {
        ++x;
        return string {"dumb_return_value"};
    }
};

class multiply{
public : 
    string operator()(int& x)
    {
        x = x * 2;
        return string {"dumb_return_value"};
    }
};

template <typename A, typename B>
class do_nothing{
public : 
    void operator()(A , B)
    {
        return;
    }
};


int main()
{
    int x = 0;
    increment increment_object;
    multiply multiply_object;
    do_nothing<string,string> do_nothing_object;

    bind(do_nothing_object,bind(increment_object,ref(x)),bind(multiply_object,ref(x)))();
    cout << x << endl;//output 2

    x = 0;
    bind(do_nothing_object,bind(multiply_object,ref(x)),bind(increment_object,ref(x)))();
    cout << x << endl;//output 1
}

compilation option : std=c++1z So, I use the reference semantics to amplify the difference here. What is the execution order of these sub-functions increment and multiply? Does bind handle this providently and define an order, or it is dependent on function parameter evaluation sequence, which is compiler-specific? If std::bind() handles this providently, please cite it, thanks!

PS: one reason why I ask this question is here: c++ equivalent of java's andThen function to composite new function?

Han XIAO
  • 1,148
  • 9
  • 20
  • 1
    Have you considered not using `std::bind` at all? By [tag:C++17], I am unaware of any convincing reason to use it over lambdas. `std::bind` was added in parallel with lambdas and initially could do some things lambdas could not; now, that isn't true. Using `std::bind` means you have to learn a whole pile of really arcane corner cases (like the above); using lambda has similar corner cases, but you'll want to learn lambdas anyhow so why not just learn one? – Yakk - Adam Nevraumont Aug 22 '18 at 14:45
  • @Yakk-AdamNevraumont I was just wondering if `bind` handle this perfectly. – Han XIAO Aug 22 '18 at 14:46
  • @Yakk-AdamNevraumont As for `java`, when trying to coin a new functor, it has the member function like `andThen` to coin a new functor with one functor executed before another. That's why I asked this question. – Han XIAO Aug 22 '18 at 14:58
  • Pretty sure this is just a regular function call and the order of evaluation of each parameter is undefined. `5.2.2/8`.. – Brandon Aug 22 '18 at 15:02
  • @Brandon The function calls in a chained bind are deferred until the outermost bind is evaluated. When you pass the result of bind to bind it acts really strange. So you'd have to find something in 20.10.9. – Yakk - Adam Nevraumont Aug 22 '18 at 15:15
  • @Yakk-AdamNevraumont; I don't see how that would work.. to me, the inner binds must be evaluated first and the results would be passed to the outer bind.. I can't see how the outer bind can bind anything without knowing what it's binding (inner binds).. – Brandon Aug 22 '18 at 16:28
  • 1
    @Brandon The inner binds are only evaluated when the outer bind is called; the bind (when std::bind is called) the inner binds are left unevaluated (their operator() is deferred until the outer bind's operator() is evaluated). `std::bind` is in many ways a strange beast, see my comment above. Part of the problem is lanuage related; there is the "point of binding" and "evaluation of bind". Inner binds are bound first. Then outer binds are bound to inner. Then when outer is evaluated, the arguments are also passed to inner to get arguments passed to outer-bound callable. – Yakk - Adam Nevraumont Aug 22 '18 at 17:16

1 Answers1

0

Using this draft as reference.

func.bind.bind [20.10.9.1.3] doesn't specify when the bind sub-expressions are evaluated or their order.

It simply states that if one of the arguments to bind is a bind-expression result, the return value of the outer bind expression uses the result of calling the inner bind-expression with the arguments passed to the outer bind expression. It gives no sequencing information for when those values are evaluated; one may presume that it "must" happen after the outer bind expression is passed arguments, but that (as far as I can tell) only something I can conclude with common sense, not from the standard text itself.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524