Search code examples
c++bind2nd

Bind2nd issue with user-defined class


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>'
}

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.