Muitas vezes precisamos implementar uma função sob demanda, ou seja, passar parâmetros de acordo com a necessidade do nosso aplicativo. E o std::placeholders
servem para isso.
O namespace std::placeholders
trabalha juntamente com a função std::bind
e precisamos incluir o cabeçalho <funcional>
para poder utilizarmos. Eles contém os objetos de placeholder [_1,..._N
] onde N é um número máximo definido pela implementação.
O template de função std::bind
retorna um objeto de função com base em fn, mas com seus argumentos vinculados a args.
Quando usado como um argumento em uma expressão std::bind
, os objetos de espaço reservado são armazenados no objeto de função gerado e quando esse objeto de função é chamado com argumentos não acoplados, cada espaço reservado _N
é substituído pelo enésimo argumento não acoplado correspondente.
extern /* não especificada */ _1; // até o c++17
;inline constexpr /* não especificada */ _1;
extern /* não especificada */ _1;
, ainda é permitido pelo padrão;DefaultConstructible
e CopyConstructible
_N
, o tipo std::is_placeholder<decltype(_N)>
;std::integral_constant<int, N>
._1
Dada a função soma_sub(int, int, int)
que retorna a soma e subtração dos parâmetros, respectivamente, se quisermos que um parâmetro seja dinâmico:
Terceiro parâmetro dinâmico
#include <iostream>
#include <functional> // para std::placeholders e std::bind
using namespace std::placeholders;
int soma_sub( int x, int y, int z ){
return x + y - z;
}
int main( int argc , char **argv ){
// substitui o z
auto fn = std::bind( soma_sub, 9, 1, _1 );
std::cout << fn( 2 ) << '\n'; // equivale soma_sub( 9, 1, 2 ) = 8
std::cout << fn( 3 ) << '\n'; // equivale soma_sub( 9, 1, 3 ) = 7
return 0;
}
Substitui o
y
auto f2 = std::bind( soma_sub, 9, _1, 1 );
std::cout << f2( 2 ) << '\n'; // equivale soma_sub( 9, 2, 1 ) = 10
std::cout << f2( 3 ) << '\n'; // equivale soma_sub( 9, 3, 1 ) = 11
Substitui o
x
auto f3 = std::bind( soma_sub, _1, 9, 1 );
std::cout << f3( 2 ) << '\n'; // equivale soma_sub( 2, 9, 1 ) = 10
std::cout << f3( 3 ) << '\n'; // equivale soma_sub( 3, 9, 2 ) = 11
Substitui o
y
e oz
, respectivamente_1
e_2
. Como estamos usando o parâmetro_2
, precisamos passar 2 parâmetros, caso contrário gera erro ao compilar.
auto f4 = std::bind( soma_sub, 1, _1, _2 );
std::cout << f4( 1, 2 ) << '\n'; // equivale soma_sub( 1, 1, 2 ) = 1 + 1 - 2 = 0
std::cout << f4( 3, 10 ) << '\n'; // equivale soma_sub( 1, 3, 10 ) = 1 + 3 - 10 = -6
Substitui o
z
e oy
, respectivamente_2
e_1
auto f5 = std::bind( soma_sub, 1, _2, _1 );
std::cout << f5( 1, 2 ) << '\n'; // equivale soma_sub( 1, 2, 1 ) = 1 + 2 - 1 = 2
std::cout << f5( 3, 10 ) << '\n'; // equivale soma_sub( 1, 10, 3 ) = 1 + 10 - 3 = 8
_2 = y
,x = 1
,z = 3
. Tem que passar 2 parâmetros(senão não compila), mas o 1º será ignorado!
auto f6 = std::bind( soma_sub, 1, _2, 3 );
// | |_________________________________
// | |
// |__________________________________ |
// | |
// ignorado | |
// ↓ | |
std::cout << f6( 897, 0/* _2 */ ) << '\n'; // equivale soma_sub( 1, 0, 3 ) = 1 + 0 - 3 = -2
// ignorado
// ↓
std::cout << f6( 800, 2/* _2 */ ) << '\n';// equivale soma_sub( 1, 2, 0 ) = 1 + 2 - 0 = 2
Pra entender de vez!
x = _3
, precisa informar 3 parâmetros(senão não compila), pois está usando o_3
, mas os dois primeiros serão ignorados.
auto f7 = std::bind( soma_sub, _3, 1, 3 );
std::cout << f7( 0, 0, 30 ) << '\n'; // z = 8 , equivale soma_sub( 1, 3, 8 ) = 30 + 1 - 3 = 28
Nova função de nome
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("Olá, marcadores de posição");
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!"; // declarada e inicializada no exemplo anterior!
fn2( name );
namespace
Exemplo final sem explicações, exercício!
#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;
}
Curiosidades: Se você o
std::bind
puro, ele pode lhe dar um resultado incorreto. Outra coisa também é se você usa obind
da libboost
:boost::bind
não é compatível com astd::bind
.
Então se inscreva nos nossos Cursos de C++ Moderno . Você aprender criar:
Acesse o endereço: