Search code examples
c++templatesbindfunctor

C++ functor binding


i tried to use the old bind2nd function in this way:

template<typename T>
class printer
{
public:
  void operator()(T a, string& kd)
  {
        cout<<a<<endl;
  }
};


int main(int argc, char *argv[])
{
   string nme = "J-dar";
   auto f1 = bind2nd(printer<int>(),nme);

   //f1(5);
   return 0;
}

but i get a lot of errors:

required from here
error: no type named 'first_argument_type' in 'class printer<int>'  class binder2nd        ^
error: no type named 'second_argument_type' in 'class printer<int>'    typename _Operation::second_argument_type value;                                              ^
error: no type named 'second_argument_type' in 'class printer<int>'    binder2nd(const _Operation& __x,    ^
error: no type named 'result_type' in 'class printer<int>'    operator()(const typename _Operation::first_argument_type& __x) const    ^
error: no type named 'result_type' in 'class printer<int>'    operator()(typename      _Operation::first_argument_type& __x) const    ^
required from here
error: no type named 'second_argument_type' in 'class printer<int>'    typedef typename _Operation::second_argument_type _Arg2_type;                                           

from what i can see it's all correct so i don't really know what is going on. ^


Solution

  • First of all: I would recommend using abandoning bind1st() and bind2nd(), which are deprecated in C+11, and in general the obsolete support for functional programming of the C++03 Standard Library.

    You should rather use C++11's std::bind(), since it seems you can afford that - judging from the fact that you are using the auto keyword:

    #include <functional>
    
    // ...
    
    auto f1 = std::bind(printer<int>(), std::placeholders::_1, nme);
    

    This said, just for the record, the deprecated std::bind2nd() function requires some metadata about the signature of your functor's call operator, and it expects these metadata to be provided as type aliases in your functor class. For instance:

    template<typename T>
    class printer
    {
    public:
    
        // These metadata must be present in order for bind1st and bind2nd to work...
        typedef void result_type;
        typedef T first_argument_type;
        typedef string const& second_argument_type;
    
        void operator()(T a, string const& kd) const
    //                                         ^^^^^ // Bonus advice #1:
    //                                               // This could and should be
    //                                               // const-qualified
    //                              ^^^^^
    //                              Bonus advice #2: why not taking by
    //                              reference to const here? ;)
        {
            cout<<a<<endl;
        }
    };
    

    A simpler way of achieving the above is to use the (also deprecated) class template std::binary_function as a base class, and let that class template define the appropriate type aliases:

    template<typename T>
    class printer : public std::binary_function<T, string const&, void>
    //              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    {
    public:
        void operator()(T a, string const& kd) const
        {
            cout<<a<<endl;
        }
    };
    

    But again, please consider putting std::bind1st(), std::bind2nd(), as well as std::unary_function and std::binary_function, back in the drawer. They are superseded by C++11's more powerful support for functional programming.