0

I'm trying to learn how to use bind2nd with user-defined classes, but I'm getting an error that I can't figure out how to fix despite my efforts of looking into other resources for assistance.

Help would be appreciated, thank you.

main.cpp

#include <algorithm>
#include <vector>

class F
{
public:
  int operator()(int a, int b)
  {
    return a * b;
  }
};

int main(void)
{
  std::vector<int> bases;

  for(int i = 0; i < 5; ++i)
    bases.push_back(i);

  std::transform(bases.begin(), bases.end(), bases.begin(), std::bind2nd(F(), 2));
  // Error C2664: '_OutIt std::transform<std::_Vector_iterator<_Myvec>,std::_Vector_iterator<_Myvec>,
  // std::binder2nd<_Fn2>>(_InIt,_InIt,_OutIt,_Fn1)' : cannot convert parameter 4 from
  // 'std::binder2nd<_Fn2>' to 'std::binder2nd<_Fn2>'
}
Tundra Fizz
  • 473
  • 3
  • 10
  • 25

2 Answers2

2

First of all you've to include functional to use the binder functionality.

Second you need to specify your operator() to be const.

Third, in order to get the type traits information, like *first_argument_type* and so on, it is best, in your case, to inherit from std::binary_function.

#include <algorithm>
#include <vector>
#include <functional>
#include <iterator>
#include <iostream>

struct F : public std::binary_function<int, int, int>
{
    int operator()(int a, int b) const
    {
        return a * b;
    }
};

int main(void)
{
    std::vector<int> bases;

    for(int i = 0; i < 5; ++i)
        bases.push_back(i);

    std::transform(bases.begin(), bases.end(), bases.begin(), std::bind2nd(F(), 2));

    // print it to stdout
    std::copy(bases.begin(), bases.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
}

Edit

If you've access to a C++11 aware compiler and stdlib, your vector filling code can be easily rewritten to:

std::vector<int> bases(5);
int i = 0;

std::generate(bases.begin(), bases.end(), [&i]() { return ++i; });

With C++11 there is a new binder (moved from boost::bind) std::bind. This is far more flexible and you might give it a try, if you want to. Such as:

using namespace std::placeholders;
std::transform(std::begin(bases), std::end(bases), std::begin(bases), 
               std::bind(F(), 2, _1));

(I just have seen, from the answer below, that a.lasram mentioned the new std::bind. I don't know if you're allowed in your project, or whatever, to use new C++11, instead of old C++03 functionality. If I were you, I would, if you're not allowed, well then (to quote from famous Mr. Alexandrescu) "Call your agent." :) )

Btw. Ryan (see the comments) is absolutely right, when he mentions, that even my most elaborate std::generate thing ;) can be shorter written using iota:

std::iota(bases.begin(), bases.end(), 1);

std::iota is defined in numeric. So you've to include that as well.

Hope that helps.

Stefan
  • 221
  • 2
  • 7
  • @Leif cheers sir! thank you for accepting it...please see my update for further information. you could even exchange your std.begin() to range based begin and end... – Stefan Jul 21 '13 at 20:52
  • Actually, the vector filling code can be simplified even more by calling [`std::iota`](http://en.cppreference.com/w/cpp/algorithm/iota), as in `std::iota(std::begin(bases), std::end(bases), 0)`. –  Jul 21 '13 at 20:59
  • @RyanMcK not the first time i've overseen iota...maybe because its short name ;) – Stefan Jul 21 '13 at 21:12
2

This completes Stefan's answer who pointed that std::bind takes a const reference as a functor argument and therefore operator () has to be const.

Now, your binary functor must be adaptable to std::bind2nd. bind2nd expects F to typedef first_argument_type, second_argument_type and result_type.

class F
{
public:
    typedef int first_argument_type;
    typedef int second_argument_type;
    typedef int result_type;

    int operator()(int a, int b) const
    {
        return a * b;
    }
};

C++11 introduces std::bind a more generic and flexible solution that does not have these required typedefs

a.lasram
  • 4,371
  • 1
  • 16
  • 24