Полиморфные функторы в std::for_each
-
03-07-2019 - |
Вопрос
Я пытаюсь использовать алгоритм stl for_each без распространения шаблонов по всему моему коду.std::for_each хочет создать экземпляр класса MyFunctor по значению, но не может, поскольку он абстрактный.Я создал класс адаптера функтора, который передает указатель по кругу, а затем разыменовывает его при необходимости.
Мой Вопрос:
Есть ли у STL или Boost уже такой класс адаптера?Я не хочу изобретать велосипед заново!
struct MyFunctor {
virtual ~MyFunctor() {}
virtual void operator()(int a) = 0;
}
namespace {
template<typename FunctorType, typename OperandType> struct
FunctorAdapter
{
FunctorAdapter(FunctorType* functor) : mFunctor(functor) {}
void operator()(OperandType& subject)
{
(*mFunctor)(subject);
}
FunctorType* mFunctor;
}; }
void applyToAll(MyFunctor &f) {
FunctorHelper<MyFunctor, int> tmp(&f);
std::for_each(myvector.begin(), myvector.end(), tmp); }
Ваше здоровье,
Дэйв
Решение
tr1::ref может помочь вам здесь --- это должна быть ссылочная оболочка, чтобы вы могли передавать обычные объекты по ссылке на объекты bind или function (даже абстрактные) по ссылке на стандартные алгоритмы.
// requires TR1 support from your compiler / standard library implementation
#include <functional>
void applyToAll(MyFunctor &f) {
std::for_each(
myvector.begin(),
myvector.end(),
std::tr1::ref(f)
);
}
Однако обратите ВНИМАНИЕ, что компиляторы без поддержки decltype мочь отклоните передачу ссылки на абстрактный тип...таким образом, этот код может не скомпилироваться, пока вы не получите поддержку C ++ 0x.
Другие советы
Вы могли бы использовать функциональные адаптеры (и их прокладки) из functional
.
#include <functional>
using namespace std;
for_each( vec.begin(), vec.end(), :mem_fun_ptr( &MyClass::f ) );
Если ваш контейнер содержит указатели на объекты, используйте mem_fun_ptr
, иначе используйте mem_fun
.Рядом с ними находятся оболочки для функций-членов, которые принимают 1 аргумент: mem_fun1_ptr
и mem_fun1
.
@Эван:действительно, вы могли бы вызвать функцию-член с одним и тем же аргументом для каждого объекта.Первый аргумент в mem_fun1
обертки - это this
указатель, второй - это аргумент функции-члена:
for_each( vec.begin(), vec.end(), bind2nd( mem_fun_ptr( &MyClass::f ), 1 ) );
С большим количеством аргументов становится более удобным создавать цикл самостоятельно или создавать пользовательский функтор, содержащий переменные-члены const, представляющие аргументы.
почему бы не использовать BOOST_FOREACH?
Похоже, вы могли бы извлечь выгоду из Повышение:: Функция.
Если я правильно помню, это тоже библиотека только для заголовков, так что с ней легко работать.
Как насчет того, чтобы забыть обо всем переносе указателя функтора и вместо этого использовать
bind(functor_pointer,mem_fun1(&MyFunctor::operator());
как функтор?таким образом, вам не нужно беспокоиться об управлении копией каким-либо образом.
Основываясь на ответе @xtofl , поскольку массив содержит указатели int, а не "this", я думаю, что правильное заклинание
class MyClass
{
virtual void process(int number) = 0;
};
MyClass *instance = ...;
for_each( vec.begin(), vec.end(), binder1st(instance, mem_fun_ptr(&MyClass::process) );
Единственное отличие от кода @xtofl - это binder1st, а не binder2nd.binder2nd позволяет вам передавать один и тот же номер различным указателям "this".binder1st позволяет вам передавать различные числа одному указателю "this".