Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When using bind(), arguments are passed by reference even if ref() adaptor is not used

Tags:

c++

c++11

I have the following C++11 code:

#include <iostream>
#include <functional>

using namespace std;
using namespace placeholders;

void f(int a, int b)
{
    cout << a << " " << b << endl;
}

void g(int& a, int& b)
{
    a *= 2;
    b *= 3;
}

int main()
{
    int a = 100;
    int b = 200;
    auto greversed = bind(g,_2,_1);
    greversed(b,a);
    f(a,b);
    greversed(ref(b),ref(a));
    f(a,b);
}

Based on my reading of "The C++ Programming Language 4th Edition" (Stroustrup) p. 968 I would expect that during the first call to greversed(b,a) that a copy of a and b would be passed by reference to g() and that only the second call would actually pass a and b to g() by reference.

The example code given on p. 968:

void incr(int& i)
{
    ++i;
}

void user()
{
    int i =1;
    incr(i);                     // i becomes 2
    auto inc = bind(incr,_1);
    inc(i);                     // i stays 2; inc(i) incremented a local copy of i
}

Running this code, i is incremented twice, despite what the comments say.

For my program, my expected output would be:

100 200
200 600

However, when I compile this code under Ubuntu using "g++ -std=c++11 test.cpp" I get the following output:

200 600
400 1800

It appears a and b are passed by reference no matter if the ref() adaptor are used or not.

like image 682
lowlandsolution Avatar asked Jun 13 '14 15:06

lowlandsolution


People also ask

What happens when an argument is passed by reference?

Pass-by-reference means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the argument by using its reference passed in. The following example shows how arguments are passed by reference.

How arguments are passed to a function using references?

The call by reference method of passing arguments to a function copies the reference of an argument into the formal parameter. Inside the function, the reference is used to access the actual argument used in the call. This means that changes made to the parameter affect the passed argument.

Why is it important to bind a function to its arguments?

Bind function with the help of placeholders helps to manipulate the position and number of values to be used by the function and modifies the function according to the desired output.

Why pass by reference instead of value?

Passing a variable The terms “pass by value” and “pass by reference” are used to describe how variables are passed on. To make it short: pass by value means the actual value is passed on. Pass by reference means a number (called an address) is passed on which defines where the value is stored.


1 Answers

Introduction

std::placeholders::_* works by perfectly-forwarding the types which later takes their place.

This mean that since you are passing a and b (which are lvalues) to greversed these lvalues will be forwarded to g, exactly like they are.


This behavior is explained in section [func.bind.bind]p10 of the Standard (n3337), but a more easy to understand explanation can be found here:

  • cppreference.com - std::bind

Source of confusion

I haven't read the book you are referring to, but your confusion probably lies in the fact that std::bind will not bind a reference to the passed in argument when you use a non-placeholder, instead it will copy the argument.

This below example hopefully aids in understanding the difference between using a std::placeholder, and passing in a value to be bound.

int main () {
  auto f = [](int& r1, int& r2) {
    r1 *= 2;
    r2 *= 2;
  };

  int  a = 1;
  int  b = 2;

  auto x = std::bind (f, a, std::placeholders::_1); // a copy of `a` will be stored
                                                    // inside `x`

  x (b);  // pass the copy of `a`, and perfectly-forward `b`, to `f`
              
  std::cout << "a: " << a << std::endl; 
  std::cout << "b: " << b << std::endl;
}
a: 1
b: 4
like image 189
Filip Roséen - refp Avatar answered Sep 18 '22 14:09

Filip Roséen - refp