Search code examples
c++c++11c++14bindstdbind

can't assign std::bind return value to std::function


I have been trying to write a very simple piece of code but it doesn't seems to work and I am unable to make any sense out of the compiler error.

code:

#include <iostream>
#include <sstream>
#include <functional>

class c
{
public:
    void test(std::stringstream ss){
        std::cout<<ss.str()<<std::endl;
    }

    void test2(std::stringstream ss){
        const auto bound=std::bind(&c::test,this, ss);
        std::function<void()> f(bound);
        f();
    }

};

void test1(const std::stringstream ss){
    std::cout<<ss.str()<<std::endl;
}

int main(){         
    std::stringstream ss;
    ss<<"hello world";

    //first
    const auto bound=std::bind(&test1,ss);
    std::function<void()> f(bound);
    f();
    //second
    C obj;
    obj.test2(ss);
    return 0;               
}                   

error:

bind.cpp:14:32: error: no matching function for call to ‘std::function<void()>::function(const std::_Bind<std::_Mem_fn<void (c::*)(std::__cxx11::basic_stringstream<char>)>(c*, std::__cxx11::basic_stringstream<char>)>&)’
  std::function<void()> f(bound);
                               ^
bind.cpp:30:31: error: no matching function for call to ‘std::function<void()>::function(const std::_Bind<void (*(std::__cxx11::basic_stringstream<char>))(std::__cxx11::basic_stringstream<char>)>&)’
  std::function<void()> f(bound);
                               ^

I am compiling with: g++ -std=c++14 bind.cpp. I see here where the accepted answer suggested to use lambdas instead of std::bind but, can anybody tell why both first and second usage in the above code does not work?


Solution

  • The problems you are facing have to do with the fact that std::stringstream does not have a copy constructor.

    The problems can be resolved by using const std::stringstream& as argument types instead of std::stringstream in couple of functions.

    #include <iostream>
    #include <sstream>
    #include <functional>
    
    class c
    {
      public:
    
        // Change the argument to a const&
        void test(std::stringstream const& ss){
            std::cout<<ss.str()<<std::endl;
        }
    
        // Use std::cref to use a const& in the call to std::bind
        void test2(std::stringstream ss){
            const auto bound=std::bind(&c::test,this, std::cref(ss));
            std::function<void()> f(bound);
            f();
        }
    
    };
    
    // Change the argument to a const&
    void test1(const std::stringstream & ss){
        std::cout<<ss.str()<<std::endl;
    }
    
    int main(){         
        std::stringstream ss;
        ss<<"hello world";
    
        //first
        // Use std::cref to use a const& in the call to std::bind
        const auto bound = std::bind(&test1, std::cref(ss));
        std::function<void()> f = bound;
        f();
        return 0;               
    }