3

I'm trying to understand how std::bind and std::function work. I cannot get the following code to compile:

#include <iostream>
#include <string>
#include <functional>

void function(int a, float b, std::string const &s)
{
    std::cout << "printing function" << std::endl;
    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << s << std::endl;
}

int main(int argc, char *argv[])
{
    std::bind(&function, 10, 11.1, "hello")();
    std::function<void(int, float, std::string const&)> fun = std::bind(&function, 10, std::placeholders::_1, std::placeholders::_2);

    fun(0.2, "world");

    return 0;
}

the compiler complains that:

main.cpp: In function 'int main(int, char**)':
main.cpp:16:69: error: conversion from 'std::_Bind_helper<false, void (*)(int, float, const std::__cxx11::basic_string<char>&), int, const std::_Placeholder<1>&, const std::_Placeholder<2>&>::type {aka std::_Bind<void (*(int, std::_Placeholder<1>, std::_Placeholder<2>))(int, float, const std::__cxx11::basic_string<char>&)>}' to non-scalar type 'std::function<void(int, float, const std::__cxx11::basic_string<char>&)>' requested
  std::function<void(int, float, std::string const&)> fun = std::bind(&function, 10, std::placeholders::_1, std::placeholders::_2);
                                                            ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

please, can someone explain? and how do I fix this error?

Luca
  • 1,658
  • 4
  • 20
  • 41
  • 1
    Once you've bound `a` to `10`, what remains is just `void(float, std::string const&)`. – Quentin Mar 12 '19 at 14:59
  • Also note, that `std::bind` is deprecated in C++17, and that using lambda is more preferred. `auto fun = [](float a, std::string const& b) { function(10, a, b); };` – Zereges Mar 12 '19 at 15:02
  • 2
    It might be worth pointing out that in modern code, lambdas are always preferable to std::bind now. –  Mar 12 '19 at 15:03
  • 2
    @Zereges `std::bind` is in no way deprecated. `std::bind1st` etc. are deprecated but `std::bind` still has some uses: http://www.sdowney.org/2017/06/why-stdbind-cant-be-formally-deprecated/ – Alan Birtles Mar 12 '19 at 15:06
  • @AlanBirtles You're right, I have no idea why I thought it's deprecated – Zereges Mar 12 '19 at 15:09

1 Answers1

8

You are almost there, just change the type of fun to

std::function<void(float, std::string const&)> fun = std::bind(...);
//                ^^ no more int here

fun(0.2, "world");
//  ^^^^^^^^^^^^ those types must match the above signature

Note that you change the function signature when fixing the first function argument of type int to the value 10. Hence, it can't be in the type of the std::function instantiation.

Further note that Scott Meyers suggests in Item 34 of Effective Modern C++ to replace the std::bind usage with a lambda, e.g.

auto fun = [](float b, std::string const& s){ function(10, b, s); };

// Identical invocation:
fun(0.2, "world");
lubgr
  • 37,368
  • 3
  • 66
  • 117