Bool operator() ( int_argument1 ) const

{

returndividesOn( _argument1, 2 );

}

};

 

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

 

Связыватель верхнего уровня, в свою очередь, применяет операцию логического отрицания к результату выполнения связывателя нижнего уровня. Общий результат отправляется в алгоритм std::count_if и решает исходную задачу.

 

std::bind(

std::logical_not< bool>(),

std::bind( & dividesOn, std::placeholders::_1, 2 )

)

 

Средство std::bind очень гибкое и допускает массу вариантов. В качестве первого аргумента такого связывателя может использоваться любая вызываемая сущность. В качестве остальных аргументов могут быть представлены такие варианты:

● конечные вычисляемые выражения, например, константы;

● “местодержатели” std::placeholder;

● вложенные вызываемые сущности, в том числе вложенные связыватели std::bind.

 

Чтобы понять его истинную мощь, попробуем создать предикат, который выбирает числа делящиеся без остатка на 2, но не делящиеся на 3. Для этого понадобится такой вызов:

 

std::cout

<< std::count_if(

v.begin(), v.end(),

// Связыватель верхнего уровня

 

std::bind(

// Логическое И над двумя дочерними предикатами

std::logical_and< bool>(),

// Деление на 2

std::bind( & dividesOn, std::placeholders::_1, 2 ),

// Логическое отрицание деления на 3

std::bind(

std::logical_not< bool>(),

std::bind( &dividesOn, std::placeholders::_1, 3 )

)

)

)

<< std::endl;

 

Реализация универсального связывания std::bind и “местодержателей” основывается на формировании так называемых кортежей (std::tuple - N-мерной эволюции понятия std::pair), а также списков типов (typelists), и доступу к их элементам по индексам. Это достаточно сложные механизмы языка и стандартной библиотеки, далеко выходящие за рамки данного курса.

 

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

 

 

Теоретически, такую формулу можно закодировать при помощи комбинации стандартных функторов и связывателей std::bind. Однако, переваривать такое “блюдо” рады немногие программисты:

 

// R = 3 * X / ( Y + 2 )

std::transform(

vX.begin(), vX.end(), vY.begin(),

std::back_inserter( vR ),

std::bind< double>(

std::divides< double>(), // деление

std::bind< double>( // числитель

std::multiplies< double>(),

3.0,

std::placeholders::_1

),

std::bind< double>( // знаменатель

std::plus< double>(),

std::placeholders::_2,

2.0

)

)

);

 

Хотя кодирование в таком стиле имеет своих фанатов, и цепочка связывателей всего лишь повторяет дерево вычисления выражения, а генерируемый машинный код весьма эффективен, большинство программистов сочтет такой код нечитабельным и неоднозначным. Сложность восприятия ограничивает применимость подобных приемов.