Home > Net >  How to pass reference value to a std::function from one class to another class
How to pass reference value to a std::function from one class to another class

Time:07-16

I have the following scenario.

File Box.h
#pragma once
#include <functional>

class Box
{
    public:
        Box() :m_data(45) {}
        void set_callback(std::function<int(int, int& c)> cb)
        {
            f = cb;
        }
        auto get_box_dimension(void)
        {
             return f(4,m_data);
        }
    

private:
    std::function<int(int, int&)> f;
    int m_data;
};

File SquareBox.h
#pragma once
#include <functional>

class SquareBox
{
public:
    int sq_func(int a, int& b)
    {
        return a * b;
    }

private:


};

File main.cpp
#include<iostream>
#include<functional>
#include"Box.h"
#include"SquareBox.h"

int main()
{
    int x = 1;
    int a = 5;
    Box b;
    SquareBox sq_box;
    b.set_callback(std::bind(&SquareBox::sq_func,&sq_box,a,x));
    int ret_val = b.get_box_dimension();
    std::cout << "Return Value == " << ret_val << std::endl;
    return 0;
}

I was expecting the answer to be 5 times 45 . 45 being passed from the class Box. But the answer is 5. How can I make sure that the sq_func receives the value of second argument from class Box m_data ?

CodePudding user response:

std::bind is rather old-fashioned and quirky. Most uses are simpler with a lambda expression. Specifically you tripped over this detail (see cppreference):

If some of the arguments that are supplied in the call to g() are not matched by any placeholders stored in g, the unused arguments are evaluated and discarded.

In other words: Apart from the implicit this, sq_func takes 2 parameters, you already bound 2 hence the two parameters passed when you call f(4,m_data) are discarded. You should only bind the parameters that you will not pass later and use placeholders for the ones you do not want to bind (_1,_2,etc).

If you want to capture sq_box and a then the resulting callable has only a single argument not two. I don't understand why you bind x nor why you pass 4 when calling it. Anyhow, you get expected output when you change the function type to std::function<int(int&)> and use a lambda expression to bind the parameters:

#include <functional>
#include <iostream>
struct Box {
    Box() :m_data(45) {}
    void set_callback(std::function<int(int& c)> cb) { f = cb; }
    auto get_box_dimension() { return f(m_data); }
private:
    std::function<int(int&)> f;
    int m_data;
};

struct SquareBox {
    int sq_func(int a, int& b) { return a * b; }
};

int main() {
    int a = 5;
    Box b;
    SquareBox sq_box;
    b.set_callback([&sq_box,a](int& v){ return sq_box.sq_func(a,v);});
    int ret_val = b.get_box_dimension();
    std::cout << "Return Value == " << ret_val << std::endl;
}

Note that I captured a by value. If you want to set eg a = 42 and then calling b.get_box_dimension() should reflect that you can capture it by reference as well.

  • Related