-2

I came across this code. From the output I could infer that remainder array stores the remainder of numbers array when divided by 2. But the syntax is unfamiliar to me.

#include <iostream>
#include <functional>
#include <algorithm>

using namespace std;

int main ( )
{

    int numbers[ ] = {1, 2, 3};

    int remainders[3];

    transform ( numbers, numbers + 3, remainders, bind2nd(modulus<int>( ), 2) );

    for (int i = 0; i < 3; i++)
    {
        cout << (remainders[i] == 1 ? "odd" : "even") << "\n";
    }
    return 0;

}

What do transform and bind2nd do in this context? I read the documentation but it was not clear to me.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Akriti Anand
  • 166
  • 3
  • 17

2 Answers2

5

std::bind2nd is an old function for binding a value to the second parameter of a function. It has been replaced by std::bind and lambdas.

std::bind2nd returns a callable object that takes one parameter and calls the wrapped callable with that parameter as its first parameter and the bound parameter as its second parameter:

int foo(int a, int b)
{
    std::cout << a << ' ' << b;
}

int main()
{
    auto bound = std::bind2nd(foo, 42);
    bound(10); // prints "10 42"
}

std::bind2nd (and its partner std::bind1st) were deprecated in C++11 and removed in C++17. They were replaced in C++11 by the more flexible std::bind as well as lambda expressions:

int foo(int a, int b)
{
    std::cout << a << ' ' << b;
}

int main()
{
    auto bound = std::bind(foo, std::placeholders::_1, 42);
    bound(10); // prints "10 42", just like the std::bind2nd example above

    auto lambda = [](int a) { foo(a, 42); };
    lambda(10); // prints "10 42", same as the other examples
}

std::transform calls a callable on each element of a range and stores the result of the call into the output range.

int doubleIt(int i)
{
    return i * 2;
}

int main()
{
    int numbers[] = { 1, 2, 3 };
    int doubled[3];

    std::transform(numbers, numbers + 3, doubled, doubleIt);
    // doubled now contains { 2, 4, 6 }
}
Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
3

std::bind2nd is from C++98/03 (specifically, pre-lambdas).

bin2nd(f, x) assumes that f is a function (or at least something that can be invoked like a function) and x is a value that an be passed to that function as its second parameter. It creates something that acts like a function. When you call the function it creates, it's equivalent to calling f(something, x), so it binds x to the second parameter of its input function.

Nowadays, you'd probably write this more like:

transform(std::begin(numbers), std::end(numbers), 
          remainders, 
          [](int x) { return x % 2; });

As for what transform does, it's pretty much like a loop, so this is roughly equivalent to:

for (int i=0; i<3; i++)
    remainders[i] = numbers[i] % 2;

Overall, I think the original code is kind of half-baked. It looks to me like it was probably written when all this stuff was fairly new (or at least new to the author). If I were going to do this job overall, I'd probably "collapse" the operations together a bit:

std::transform(std::begin(numbers), std::end(numbers),
            std::ostream_iterator<std::string>(std::cout, "\n"), 
            [](int i) { return std::to_string(i) + (i % 2 == 0 ? " is even" : " is odd"); });

The original doesn't seem to have any use for the remainders array except to hold an intermediate value before printing out the result, so it's probably better not to create/populate it at all.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111