Question

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>'
}
Was it helpful?

Solution

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.

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top