Sometimes we want to be able to bind to a method so we can call it directly, or more likely pass that function around. There are a few ways to do this. One is via a proxy function like:
void proxy_function (int cash, BankAccount<int> &b)
{
b.deposit(cash);
}
auto f1 = std::bind(proxy_function, _1, account1);
f1(100);
Or without the proxy:
auto f2 = std::bind(&BankAccount<int>::deposit, &account1, _1);
f2(100);
Here is the full example:
#include <algorithm> // for std::move
#include <functional> // for _1, _2
#include <iostream>
#include <memory>
#include <sstream> // for std::stringstream
#include <string>
#include <utility>
using namespace std::placeholders; // for _1, _2, _3...
template < class T > class BankAccount;
template < class T > class BankAccount
{
private:
const T no_cash {};
T cash {};
public:
BankAccount() { std::cout << "default constructor " << to_string() << std::endl; }
BankAccount(T cash) : cash(cash) { std::cout << "new cash " << to_string() << std::endl; }
BankAccount(const BankAccount &o)
{
std::cout << "copy cash constructor called for " << o.to_string() << std::endl;
cash = o.cash;
std::cout << "copy cash constructor result is " << to_string() << std::endl;
}
// Transfer of funds?
BankAccount(BankAccount< T > &&o)
{
std::cout << "move cash called for " << o.to_string() << std::endl;
cash = o.cash;
o.cash = no_cash;
std::cout << "move cash result is " << to_string() << std::endl;
}
~BankAccount() { std::cout << "delete account " << to_string() << std::endl; }
void deposit(const T &deposit)
{
cash += deposit;
std::cout << "deposit cash called " << to_string() << std::endl;
}
using CheckTransactionCallback = std::function< void(T) >;
int check_transaction(int cash, CheckTransactionCallback fn)
{
if (cash < 100) {
throw std::string("transaction is too small for Mr Money Bags");
} else {
fn(cash);
}
return cash;
}
T balance(void) const { return cash; }
bool check_balance(T expected) const
{
if (cash == expected) {
return true;
} else {
throw std::string("account has different funds " + to_string() + " than expected " + std::to_string(expected));
}
}
friend std::ostream &operator<<(std::ostream &os, const BankAccount< T > &o)
{
os << "$" << std::to_string(o.cash);
return os;
}
std::string to_string(void) const
{
auto address = static_cast< const void *>(this);
std::stringstream ss;
ss << address;
return "BankAccount(" + ss.str() + ", cash $" + std::to_string(cash) + ")";
}
};
void proxy_function(int cash, BankAccount< int > &b) { b.deposit(cash); }
int main(int, char **)
{
try {
// create account1 and try to deposit into it
auto account1 = BankAccount< int >(0);
// invoke a bind to a method via proxy
auto f1 = std::bind(proxy_function, _1, account1);
f1(100);
//
// std::ref is not normally needed unless it is something, like
// say a bitfield that cannot have a direct reference and needs
// to be wrapped by std::reference
//
// invoke a bind to a method via proxy with std::ref
auto f2 = std::bind(proxy_function, _1, std::ref(account1));
f2(100);
// invoke a bind to a method directly
auto f3 = std::bind(&BankAccount< int >::deposit, &account1, _1);
f3(100);
// check the deposits succeeded
account1.check_balance(300);
// end
} catch (const std::string &e) {
std::cerr << "FAILED: account1 deposit failed!: " << e << std::endl;
}
}
To build:
cd std_bind_with_a_method rm -f *.o example clang -std=c++2a -Werror -g -O3 -fstack-protector-all -ggdb3 -Wall -c -o main.o main.cpp clang main.o -lstdc++ -o example ./example
Expected output:
�[31;1;4mcreate account1 and try to deposit into it�[0m new cash BankAccount(0x7ffc573b6150, cash $0) �[31;1;4minvoke a bind to a method via proxy�[0m copy cash constructor called for BankAccount(0x7ffc573b6150, cash $0) copy cash constructor result is BankAccount(0x7ffc573b6168, cash $0) deposit cash called BankAccount(0x7ffc573b6168, cash $100) �[31;1;4minvoke a bind to a method via proxy with std::ref�[0m deposit cash called BankAccount(0x7ffc573b6150, cash $100) �[31;1;4minvoke a bind to a method directly�[0m deposit cash called BankAccount(0x7ffc573b6150, cash $200) �[31;1;4mcheck the deposits succeeded�[0m delete account BankAccount(0x7ffc573b6168, cash $100) delete account BankAccount(0x7ffc573b6150, cash $200) # FAILED: account1 deposit failed!: account has different funds BankAccount(0x7ffc573b6150, cash $200) than expected 300