We often need to implement a function on demand, that is, pass parameters according to the needs of our application. And std::placeholders
are for that.
The std::placeholders
namespace works together with the std::bind
function and we need to include the <functional>
header in order to use it. They contain placeholder objects [_1, ..._ N
] where N is a maximum number defined by the implementation.
The std::bind function template returns a function object based on fn, but with its arguments linked to args.
When used as an argument in a std::bind
expression, placeholder objects are stored in the generated function object and when that function object is called with unbound arguments, each _N
placeholder is replaced with the corresponding umpteenth unbound argument .
Connections characteristics and placeholders
extern / * not specified * / _1; // up to c ++ 17
;inline constexpr / * unspecified * / _1
;extern / * unspecified * / _1
; , is still allowed by the standard;_N
placeholder, type std::is_placeholder<decltype (_N)>
;std::integral_constant<int, N>
._1
Given the function sum_sub(int, int, int)
which returns the sum and subtraction of the parameters, respectively, if we want a parameter to be dynamic:
#include <iostream>
#include <functional> // para std::placeholders e std::bind
using namespace std::placeholders;
int sum_sub( int x, int y, int z ){
return x + y - z;
}
int main( int argc , char **argv ){
// replace z
auto fn = std::bind( sum_sub, 9, 1, _1 );
std::cout << fn( 2 ) << '\n'; // equal sum_sub( 9, 1, 2 ) = 8
std::cout << fn( 3 ) << '\n'; // equal sum_sub( 9, 1, 3 ) = 7
return 0;
}
replace
y
auto f2 = std::bind( sum_sub, 9, _1, 1 );
std::cout << f2( 2 ) << '\n'; // equal sum_sub( 9, 2, 1 ) = 10
std::cout << f2( 3 ) << '\n'; // equal sum_sub( 9, 3, 1 ) = 11
replace
x
auto f3 = std::bind( sum_sub, _1, 9, 1 );
std::cout << f3( 2 ) << '\n'; // equal sum_sub( 2, 9, 1 ) = 10
std::cout << f3( 3 ) << '\n'; // equal sum_sub( 3, 9, 2 ) = 11
Replaces
y
andz
, respectively_1
and_2
. As we are using parameter_2
, we need to pass 2 parameters, otherwise it generates an error when compiling.
auto f4 = std::bind( sum_sub, 1, _1, _2 );
std::cout << f4( 1, 2 ) << '\n'; // equal sum_sub( 1, 1, 2 ) = 1 + 1 - 2 = 0
std::cout << f4( 3, 10 ) << '\n'; // equal sum_sub( 1, 3, 10 ) = 1 + 3 - 10 = -6
Replaces
z
andy
, respectively_2
and_1
auto f5 = std::bind( sum_sub, 1, _2, _1 );
std::cout << f5( 1, 2 ) << '\n'; // equal sum_sub( 1, 2, 1 ) = 1 + 2 - 1 = 2
std::cout << f5( 3, 10 ) << '\n'; // equal sum_sub( 1, 10, 3 ) = 1 + 10 - 3 = 8
_2 = y
,x = 1
,z = 3
. You have to pass 2 parameters (otherwise, don’t compile), but the first one will be ignored!
auto f6 = std::bind( sum_sub, 1, _2, 3 );
// | |_________________________________
// | |
// |__________________________________ |
// | |
// ignored | |
// ↓ | |
std::cout << f6( 897, 0/* _2 */ ) << '\n'; // equal sum_sub( 1, 0, 3 ) = 1 + 0 - 3 = -2
// ignored
// ↓
std::cout << f6( 800, 2/* _2 */ ) << '\n';// equal sum_sub( 1, 2, 0 ) = 1 + 2 - 0 = 2
To understand once and for all!
x = _3
, you need to enter 3 parameters (otherwise it does not compile), because you are using_3
, but the first two will be ignored.
auto f7 = std::bind( sum_sub, _3, 1, 3 );
std::cout << f7( 0, 0, 30 ) << '\n'; // z = 8 , equal sum_sub( 1, 3, 8 ) = 30 + 1 - 3 = 28
New name function:
show_name( std::string & )
#include <iostream>
#include <functional>
namespace pl = std::placeholders;
void show_name( std::string &name ){
std::cout << name << '\n';
}
int main( int argc , char **argv ){
std::string name("Hello placeholders");
auto fn1 = std::bind( show_name, pl::_1 );
fn1( name );
return 0;
}
auto
std::function<void( std::string & )> fn2 = std::bind( show_name , pl::_1 );
name = "Like, a boss!"; // declared and initialized in the previous example!
fn2( name );
namespace
#include <iostream>
#include <functional>
int add3(int x1, int x2, int x3) {
return x1 + x2 + x3;
}
int main( int argc , char **argv ){
auto fadd3 = std::bind(add3, 11, std::placeholders::_1, std::placeholders::_2);
std::cout << fadd3(22, 33) << '\n';
return 0;
}
Trivia: If you use pure
std::bind
, it may give you an incorrect result. Another thing is also if you use lib boost bind:boost::bind
is not compatible withstd::bind
.