Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.63/48: Рейтинг темы: голосов - 48, средняя оценка - 4.63
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499

Разобраться с std::bind, плейсхолдеры

22.06.2015, 02:24. Показов 9426. Ответов 15
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, чтобы разобраться с основами std::bind написал следующий код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <functional>
#include <vector>
 
void print(int i, int j) {
    std::cout<<"--"<<std::endl;
}
 
void printt(int i, int j, int z) {
    std::cout<<i<<" "<<j<<" "<<z<<std::endl;
}
 
class CAmb {
public:
    CAmb() {}
    void printt(int i, int j, int z) {
        std::cout<<i<<" "<<j<<" "<<z<<std::endl;
    }
 
    void print(int i, int j) {
        std::cout<<i<<" "<<j<<std::endl;
    }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<CAmb> vec1(5);
    int i =  3;
    int j = 4;
    int z = 5;
 
    auto pntr1 = std::bind(std::mem_fn(&CAmb::print), std::placeholders::_1, i, j);
    auto pntr2 = std::bind(&CAmb::printt, std::placeholders::_1,  i, j, z);
    auto pntr3 = std::bind(print, i, j);
    auto pntr4 = std::bind(printt, i, j, z);
 
    return 0;
}
сам, я так и не смог разобраться почему std:: placeholders необходимы в pntr1 и pntr2(без них ошибка) и в чем принципиальная разница между, например, pntr2 и pntr4 т.е. как плейсхолдеры "меняют" привязку к функциям-членам класса и просто функциям(если написать
C++
1
auto pntr3 = std::bind(print, std::placeholders::_1, i, j);
то будет ошибка)? прошу, подскажите кто знает
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
22.06.2015, 02:24
Ответы с готовыми решениями:

Std::bind, std::mem_fun, std::mem_fn
В чем разница между функциями std::bind, std::mem_fun, std::mem_fn?

Как можно еще использовать std::placeholders вне в связки с std::bind?
Добрый день! Как можно еще использовать std::placeholders вне в связки с std::bind?

В чем отличия между std::cref() и std::bind()?
В документации не понял, что делает bind() ? И чем отличается cref() от операции взятия адреса? int x; int *y = &amp;x;...

15
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
22.06.2015, 02:38
Лучший ответ Сообщение было отмечено tapochka как решение

Решение

Цитата Сообщение от tapochka Посмотреть сообщение
std:: placeholders
обозначает, что на его месте ожидается аргумент,
с которым нужно запустить функтор.

так понятнее:

http://rextester.com/LXNV38035

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <functional>
#include <vector>
#include <iostream>
 
void print(int i, int j) {
    std::cout<<i<<" "<<j<<std::endl;
}
 
void printt(int i, int j, int z) {
    std::cout<<i<<" "<<j<<" "<<z<<std::endl;
}
 
class CAmb {
public:
    CAmb() {}
    void printt(int i, int j, int z) {
        std::cout<<i<<" "<<j<<" "<<z<<std::endl;
    }
 
    void print(int i, int j) {
        std::cout<<i<<" "<<j<<std::endl;
    }
};
 
int main()
{
    std::vector<CAmb> vec1(5);
    int i = 3;
    int j = 4;
    int z = 5;
 
    CAmb obj;
    
    auto pntr1 = std::bind(std::mem_fn(&CAmb::print), std::placeholders::_1, i, j);
    pntr1(obj);
    
    auto pntr2 = std::bind(&CAmb::printt, std::placeholders::_1,  i, j, z);
    pntr2(obj);
    
    auto pntr3 = std::bind(print, i, j);
    pntr3();
    
    auto pntr4 = std::bind(printt, i, j, z);
    pntr4();
}
Добавлено через 1 минуту
здесь доп. материал:
Применение вложенных boost::bind
1
Диванный эксперт
Эксперт С++
 Аватар для Max Dark
2550 / 2064 / 971
Регистрация: 09.10.2013
Сообщений: 4,793
Записей в блоге: 4
22.06.2015, 02:50
Лучший ответ Сообщение было отмечено tapochka как решение

Решение

bind создает новый объект-функцию из указанной функции и параметров
параметры должны соответствовать сигнатуре исходной функции
placeholders позволяют резервировать место для передачи параметров в вызове полученной функции
остальные подставляются в вызов исходной по значению

допустим есть функция int f(int, int, int)
при вызове auto f1=bind(f, _1, 1, 2); будет создан функциональный объект, принимающий 1 параметр int
и примерно равносильный объявлению
C++
1
2
3
4
int f(int, int, int);
int f1 (int _1) {
    return f(_1, 1, 2);
}
далее мы можем использовать f1 как обычную функцию с 1м параметром

с классами немного по другому: нужно помнить что передается скрытый параметр this, который компилятор приписывает в начало списка. т.е нужно указывать bind-у резервировать место под этот параметр, либо указывать с каким объектом производить связывание
1
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
22.06.2015, 03:40  [ТС]
hoggy, не подскажете почему если написать
C++
1
2
3
4
5
pntr2(obj, i);
либо
pntr2(obj, i, j);
либо
pntr2(obj, i, j, z);
записи выдают одно и то же?

Добавлено через 9 минут
Cra3y,
при вызове auto f1=bind(f, _1, 1, 2);
_1 в вашем примере это не плейсхолдер?
0
Диванный эксперт
Эксперт С++
 Аватар для Max Dark
2550 / 2064 / 971
Регистрация: 09.10.2013
Сообщений: 4,793
Записей в блоге: 4
22.06.2015, 03:43
Цитата Сообщение от tapochka Посмотреть сообщение
_1 в вашем примере это не плейсхолдер?
он самый)
0
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
22.06.2015, 04:15  [ТС]
Cra3y, можете, если не сложно, привести доходчивый пример где было бы несколько плейсхолдеров в одном байнде... не понятно пока что

Добавлено через 20 минут
нашел такой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void show(const string& a, const string& b, const string& c)
{
    cout << a << "; " << b << "; " << c << endl;
}
 
int main()
{
    auto x = bind(show, _1, _2, _3);
    auto y = bind(show, _3, _1, _2);
    auto z = bind(show, "hello", _2, _1);
     
    x("one", "two", "three");
    y("one", "two", "three");
    z("one", "two");
     
    return 0;
}
все работает на ура. Однако если написать так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class CExample {
public:
    void show(const std::string& a, const std::string& b, const std::string& c)
    {
        std::cout << a << "; " << b << "; " << c << std::endl;
    }
};
 
int main() {
auto a1 = bind(&CExample::show, _1, _2, _3);
a1("one","two","three");
 
return 0;
}
то уже будет ошибка. как реализовать байнд в примере выше чтобы при вызове a1("one","two","three"); ошибки не было?
0
Диванный эксперт
Эксперт С++
 Аватар для Max Dark
2550 / 2064 / 971
Регистрация: 09.10.2013
Сообщений: 4,793
Записей в блоге: 4
22.06.2015, 04:23
Лучший ответ Сообщение было отмечено tapochka как решение

Решение

попробую...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class test {
public:
    void some(std::fstream& out, int value) const {
        out << " called with " << this << ", " << value << std::endl;
    }
};
//....
using namespace std::placeholders; // _1, _2, etc.
test t;
auto f1 = std::bind(&test::some, _1, std::ref(std::cout), _2);
f1(t, 1); // -> t.some(std::cout, 1);
auto f2 = std::bind(&test::some, _1, _2, 2);
std::ofstream out("tmp.txt");
f2(t, out); // t.some(out, 2);
auto f3 = std::bind(&test::some, t, std::ref(out), 3); // передача t по значению, создается копия
f3(); // test t2 = t; t2.some(out, 3);
auto f4 = std::bind(&test::some, std::cref(t), std::ref(out), _1); // передача t по константной ссылке, копий нет
f4(4);// t.some(out, 4);
auto f5 = std::bind(&test::some, std::cref(t), _1, 5); // передача t по константной ссылке, копий нет
f5(std::cout);// t.some(std::cout, 5);
вместо placeholders при вызове подставляются переданные значения, на остальные места - значения переданные при bind

Добавлено через 6 минут
Цитата Сообщение от tapochka Посмотреть сообщение
чтобы при вызове a1("one","two","three"); ошибки не было?
Вы забываете о скрытом параметре this
в простейшем случае вам нужно передать в bind объект, с которым нужно вызывать эту функцию
C++
1
2
3
4
5
6
7
CExample obj;
// либо
auto a1 = bind(&CExample::show, std::ref(obj), _1, _2, _3);
a1( "1", "2", "3");
// либо
auto a2 = bind(&CExample::show, _1, _2, _3, _4);
a2(obj, "1", "2", "3");
1
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
22.06.2015, 04:27  [ТС]
спасибо, буду разбираться долго еще видимо...

чуть-чуть прояснилось с найденным примером когда show в классе сделал статической
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
22.06.2015, 10:41
Цитата Сообщение от tapochka Посмотреть сообщение
все работает на ура. Однако если написать так:
Цитата Сообщение от tapochka Посмотреть сообщение
то уже будет ошибка. как реализовать байнд в примере выше чтобы при вызове a1("one","two","three"); ошибки не было?
что бы запустить метод класса, нам нужен объект:
смотрите:

C++
1
2
auto f 
    = std::bind(свободная-функция, плейсхолдеры-или-аргументы-через-запятую);
C++
1
2
3
4
5
6
auto f 
    = std::bind(
        метод-класса,
        объект-ссылка-или-по-значению, 
        плейсхолдеры-или-аргументы-через-запятую
   );
в записи вида:
C++
1
auto pntr2 = std::bind(&CAmb::printt, std::placeholders::_1,  i, j, z);
&CAmb:rintt - метод класса,
значит следующим аргументом должен быть объект,
для которого нужно сделать запуск.

но там фигурирует плейсхолдер.
значит указать этот объект нужно при запуске функтора:

C++
1
2
3
4
5
6
CAmb obj;
    
auto pntr1 
    = std::bind(std::mem_fn(&CAmb::print), std::placeholders::_1, i, j);
 
pntr1(obj); //<--- при запуске указываем объект для которого нужно запустить метод
если бы это было вот так:
C++
1
2
3
4
5
6
7
8
CAmb obj;
auto pntr1 
    = std::bind(std::mem_fn(&CAmb::print), obj, std::placeholders::_1, j);
 
// объект уже указан (захват по значению), 
// а плейсхолдер приходится на один из аргументов запускаемой функции
 
pntr1(10); //<--- при запуске указываем недостающий аргумент i
если бы это было вот так:
C++
1
2
3
4
5
6
7
8
CAmb obj;
auto pntr1 
    = std::bind(std::mem_fn(&CAmb::print), std::placeholders::_1,std::placeholders::_2, j);
 
//плейсхолдеры приходятся и на объект
//и на аргумент i
 
pntr1(obj, 10); //<-- указываем объект, и недостающий аргумент.
std:laceholders::_1 приходится на объект для которого нужно запустить метод
std:laceholders::_2 на аргумент i.

для свободных функций все тоже самое,
только там нет объекта для которого нужно вызвать функцию:
поэтому, после объявления функции, сразу идёт биндинг аргументов:

C++
1
2
auto pntr3 = std::bind(print, i, j); //<--- нет прейсхолдеров. все аргументы забиндили
pntr3();
C++
1
2
3
//аргумент i нужно указать, аргумент j забиндили
auto pntr3  = std::bind(print,  std::placeholders::_1, j); 
pntr3(10);

в общем, все что вам нужно понять:
это разницу между биндом функции-члена, и обычной функции.

разница только в том,
что для методов класса после указания самого метода,
идет указание объекта, для которого выполняется запуск.
1
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
22.06.2015, 22:56  [ТС]
hoggy, а каково назначение std::mem_fn тут
C++
1
2
auto pntr1 
    = std::bind(std::mem_fn(&CAmb::print), std::placeholders::_1, i, j);
если прекрасно работает и без нее?
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
22.06.2015, 22:57
Цитата Сообщение от tapochka Посмотреть сообщение
если прекрасно работает и без нее?
рудимент.
0
42 / 42 / 17
Регистрация: 25.04.2014
Сообщений: 499
23.06.2015, 00:44  [ТС]
hoggy, выходит она нужна только когда в алгоритм вставляем функцию член-класса? или есть еще какое-то применение?

Добавлено через 1 час 31 минуту
Cra3y, этот код
C++
1
2
3
4
5
6
7
// либо
CExample obj;
auto a1 = bind(&CExample::show, std::ref(obj), _1, _2, _3);
a1( "1", "2", "3");
// либо
auto a2 = bind(&CExample::show, _1, _2, _3, _4);
a2(obj, "1", "2", "3");
у меня не работает(VS2012): ошибки при вызове функторов - слишком много аргументов

Добавлено через 8 минут
извиняюсь... я же ее сам статической сделал и забыл
0
 Аватар для zarko97
279 / 39 / 13
Регистрация: 11.10.2015
Сообщений: 405
05.03.2017, 17:24
hoggy, а вы случаем не знаете как через форич ввести данные в вектор пэйров?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct lambda
{
    void input(std::istream& is, std::pair<int, int>& pp)
    {
        is >> pp.first >> pp.second;
    }
};
 
int main()
{
 
    std::vector<std::pair<int, int>> v(10);
    std::for_each(v.begin(), v.end(), std::bind(std::mem_fn(&lambda::input), std::placeholders::_1, std::ref(std::cin), std::make_pair(std::placeholders::_2, std::placeholders::_3)));
    for (auto& x : v)
        std::cout << x;
}
вот на что мозгов хватило...

Добавлено через 2 часа 1 минуту
hoggy, просто у меня уже закончились догадки в чем трабл...
C++
1
2
3
4
5
6
7
8
std::for_each(v.begin(), v.end(), 
        std::bind(
            std::mem_fn(&lambda::input), 
            std::placeholders::_1, 
            std::ref(std::cin), 
            std::bind(std::make_pair<int, int>, std::placeholders::_2, std::placeholders::_3)
        )
    );
по идее эта реализация верна...но компайл еррор
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
05.03.2017, 17:32
Цитата Сообщение от zarko97 Посмотреть сообщение
вы случаем не знаете как через форич ввести данные в вектор пэйров?
http://rextester.com/CZQFI88809

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <functional>
#include <algorithm>
#include <iostream>
#include <vector>
 
void input(std::istream& is, std::pair<int, int>& pp)
{
    is >> pp.first >> pp.second;
}
 
int main()
{
    using pair_t = std::pair<int, int>;
    using vec_t  = std::vector<pair_t>;
        
    vec_t v(2);
    
    // --- первый вариант с обычной лямбдой
    // что бы было видно, какой именно функтор
    // ожидает for_each
    const auto lambda = [](pair_t& el)
    {
        std::cin >> el.first >> el.second;
    };
    
    std::for_each(v.begin(), v.end(), lambda);
    
    
    
    // --- второй вариант с биндом
    const auto getter = std::bind(input, std::ref(std::cin), std::placeholders::_1);
    
    std::for_each(v.begin(), v.end(), getter);
    
    
    for (auto&& x : v)
        std::cout << "{" << x.first << ", " << x.second <<"}; " << std::endl;
}
1
 Аватар для zarko97
279 / 39 / 13
Регистрация: 11.10.2015
Сообщений: 405
05.03.2017, 18:12
hoggy, хм...почему тогда не работает такая запись:
C++
1
2
3
4
5
6
7
8
std::vector<std::pair<int, int>> v(11);
    std::for_each(v.begin(), v.end(), 
std::bind(
            std::mem_fn(&lambda::input), 
            std::placeholders::_1,
            std::ref(std::cin), 
            std::placeholders::_2
        )
а такая работает;
C++
1
2
3
4
5
6
7
8
9
10
        lambda l;
    std::vector<std::pair<int, int>> v(11);
    std::for_each(v.begin(), v.end(), 
        std::bind(
            std::mem_fn(&lambda::input), 
            std::ref(l),
            std::ref(std::cin), 
            std::placeholders::_1
        )
    );
0
Эксперт С++
 Аватар для hoggy
8973 / 4319 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
05.03.2017, 20:38
Цитата Сообщение от zarko97 Посмотреть сообщение
почему тогда не работает такая запись
потому что вот это:

Цитата Сообщение от zarko97 Посмотреть сообщение
std::mem_fn(&lambda::input)
попытка забиндить функцию член класса.

нельзя вызывать методы классов без объектов.
это же не просто "свободные" функции.


std::bind для методов используется вот так:

auto functor = std::bind(имя-метода, объект, аргументы или плейсхолдеры);
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
05.03.2017, 20:38
Помогаю со студенческими работами здесь

std::bind
Можно ли, и если да, то как с помощью этой функции сделать следующее: auto var=std::bind(&amp;f, &quot;arg&quot;); //... //... ...

Передача std::bind в функцию
Ребята, помогите разобраться с 28 строкой. Глубоко не копал, но должно ведь компилиться :) #include &lt;iostream&gt; #include...

Std::bind с контролем типом
В общем, нужно реализовать аналог std::bind, который 1. Переводит void (*callback)(Args...) в std::function&lt;void()&gt; 2. Если среди...

Проверить объект в std::bind на живучесть
#include &lt;iostream&gt; #include &lt;string&gt; #include &lt;functional&gt; using namespace std; typedef std::function&lt;int(string)&gt; CALLBACK; ...

std::bind и указатель на статическую функцию член класса
Биндинг простых функций класса-это понятно, а вот как быть, если функция статическая?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru