Function
========
Callable concept:
#include <functional>
template < class >
class function;
template < class R, class... Args >
class function< R(Args...) >
General-purpose plymorphic function wrapper. Store, copy and invoke Callable.
Copy constructible, and copy assignable.
The callable can be:
function,
lambda expr,
bind expr,
function object,
pointer to member function
pointer to data member
target -- the stored callable.
empty -- no target
If invoked on empty functional: std::bad_function_call is thrown.
Invoke
======
template< class F, class... ArgTypes>
std::result_of_t<F&&(ArgTypes&&...)> invoke(F&& f, ArgTypes&&... args);
INVOKE( f, std::declval<ArgTypes>()..., R)
INVOKE(f, t1, t2, ..., tN) === (t1.*f)(t2, ..., tN)
INVOKE(f, t1, t2, ..., tN) === (t1.get().*f)(t2, ..., tN)
INVOKE(f, t1, t2, ..., tN) === ((*t1).*f)(t2, ..., tN)
INVOKE(f, t1) === t1.*f
INVOKE(f, t1) === t1.get().*f
INVOKE(f, t1) === (*t1).*f
INVOKE(f, t1, t2, ..., tN) === (t1, t2, ..., tN)
Member types
=============
result_type
argument_type (until C++17)
first_argument_type (until C++17)
second_argument_type (until C++17)
Member functions
================
operator=
swap
assign (until C++17)
operator bool
operator()
target_type (returns typed of target)
target (pointer to target)
Global functions
================
std::swap
operator== compares std::function with nullptr
operator!=
#include <functional>
#include <iostream>
struct Foo
{
Foo(int num) : num_(num) {}
void print_add(int i) const { std::cout << num_+i << '\n'; }
int num_;
};
void print_num(int i)
{
std::cout << i << '\n';
}
struct PrintNum
{
void operator()(int i) const
{
std::cout << i << '\n';
}
};
int main()
{
std::function<void(int)> glob = print_num;
glob(-9);
std::function<void()> lambda = []() { print_num(42); };
lambda();
std::function<void()> bind_glob = std::bind(print_num, 99);
bind_glob();
std::function<void(const Foo&, int)> mem_fun = &Foo::print_add;
const Foo foo(555);
mem_fun(foo, 1);
std::function<int(Foo const&)> mem_data = &Foo::num_;
std::cout << "num_: " << mem_data(foo) << '\n';
using std::placeholders::_1;
std::function<void(int)> mem_fun_obj = std::bind( &Foo::print_add, foo, _1 );
mem_fun_obj(2);
std::function<void(int)> mem_fun_obj_ptr = std::bind( &Foo::print_add, &foo, _1 );
mem_fun_obj_ptr(3);
std::function<void(int)> fun_obj = PrintNum();
fun_obj(18);
}
Bind
====
template< class F, class... Args >
bind( F&& f, Args&&... args );
template< class R, class F, class... Args >
bind( F&& f, Args&&... args );
Creates a forward call wrapper for f. Calling this wrapper is
like calling f with some arguments bound to args. Unbound parameters
are replaced by placeholders: _1, _2, _3, ... from std::placeholders.
#include <random>
#include <iostream>
#include <memory>
#include <functional>
void f(int n1, int n2, int n3, const int& n4, int n5)
{
std::cout << n1 << ' ' << n2 << ' ' << n3 << ' ' << n4 << ' ' << n5 << '\n';
}
int g(int n1)
{
return n1;
}
struct Foo
{
void print_sum(int n1, int n2)
{
std::cout << n1 + n2 << '\n';
}
int data = 10;
};
int main()
{
using namespace std::placeholders;
int n = 7;
auto f1 = std::bind(f, _2, _1, 42, std::cref(n), n);
n = 10;
f1(1, 2, 1001);
auto f2 = std::bind(f, _3, std::bind(g, _3), _3, 4, 5);
f2(10, 11, 12);
std::default_random_engine e;
std::uniform_int_distribution<> d(0, 10);
std::function<int()> rnd = std::bind(d, e);
for(int n=0; n<10; ++n)
std::cout << rnd() << ' ';
std::cout << '\n';
Foo foo;
auto f3 = std::bind(&Foo::print_sum, &foo, 95, _1);
f3(5);
auto f4 = std::bind(&Foo::data, _1);
std::cout << f4(foo) << '\n';
std::cout << f4(std::make_shared<Foo>(foo)) << '\n'
<< f4(std::make_unique<Foo>(foo)) << '\n';
}
Output:
2 1 42 10 7
12 12 12 4 5
1 5 0 2 0 8 2 2 10 8
100
10
10
10
Function example
================
based on http:
std::count_if(v.begin(), v.end(), is_multiple_of(n));
class is_multiple_of
{
public:
typedef bool result_type;
typedef int argument_type;
is_multiple_of(int n) : n(n) {}
bool operator()(int i) const { return i%n == 0; }
private:
const int n;
};
with lambda:
std::count_if(v.begin(), v.end(), [n](int i){return i%n == 0;} );
Find the root of f, i.e. return x where f(x) = 0
template <typename T>
double find_root( const T& f);
but there are issues with templates:
- code must be exposed in header file
- increased compilation time
- can not be virtual
how to make find_root non-template?
double find_root( const ?& f);
try decltype and auto:
auto f = [](double x) { ... };
typedef decltype(f) function_t;
unfortunately, function_t has the same scope as the lambda, we cannot use
in a different source as parameter of find_root(const function_t&)
double find_root(std::function<double(double)> const& f);
Cost
====
1. Constructor takes a functor object by value -> copy.
Forwards the copy to a number of helper functions -> further copies
e.g. MSVC and gcclib makes 4, Boost makes 7 copies!
2. Functor's size. The std::function stores the functor in a data member,
Standard recommends small object optimization, but as the size is
unknown until construction -> may be created in the heap
if f is bigger than 12bytes (MSVC), 16bytes (gcclib) or 24bytes (Boost)
Using std::reference_wrapper we can avoid ccopying.
is_multiple_of f(n);
std::count_if(v.begin(), v.end(), std::cref(f));
auto f([n](int i){return i%n == 0;});
std::count_if(v.begin(), v.end(), std::cref(f));
(Not working in Boost, should work in MSVC after 2013, works in gcclib.)
Difference between lambda and functor
======================================
Functor defines member types return_type and argument_type, lambda is not.
std::not1([n](int i){ return i%n == 0; });
std::not1(is_multiple_of(n));
auto f1([n](int i){return i%n == 0;});
std::function<bool(int)> f(std::cref(f1));
std::count_if(v.begin(), v.end(), f);
Decrease size
=============
double a;
double b;
[a, b](double x){ return a * x + b; };
double a;
double b;
struct {
const double& a;
const double& b;
} p = { a, b };
[&p](double x){ return p.a * x + p.b; };