шаблоны — Может ли Functor никогда не быть абстрактным в C ++?

Как правило, аргументы шаблонов могут быть абстрактными классами, как показано в программе ниже. Но похоже, что функтор сравнения в сортировке не должен быть абстрактным. По крайней мере, следующее не компилируется с VC ++ 11 и в Oracle Studio 12.

#include <vector>
#include <algorithm>class Functor
{
public:
virtual bool operator()(int a, int b) const = 0;
};class MyFunctor: public Functor
{
public:
virtual bool operator()(int a, int b) const { return true; }
};int _tmain(int argc, _TCHAR* argv[])
{
vector<Functor> fv; // template of abstract class is possible
vector<int> v;
MyFunctor* mf = new MyFunctor();
sort(v.begin(), v.end(), *mf);
Functor* f = new MyFunctor();
// following line does not compile:
// "Cannot have a parameter of the abstract class Functor"sort(v.begin(), v.end(), *f);
return 0;
}

Теперь мне интересно, является ли это общим свойством аргументов функтора, или это зависит от реализации STL? Есть ли способ получить то, что я хотел сделать?

6

Решение

Функторы обычно должны быть копируемыми. Полиморфные базовые классы, как правило, не копируемые и абстрактные базы никогда.

Обновить: Благодаря комментариям @ahenderson и @ltjax, вот очень простой способ создать объект-обертку, который содержит вашу исходную полиморфную ссылку:

#include <functional>

std::sort(v.begin(), v.end(), std::ref(*f));
//                            ^^^^^^^^^^^^

Результат std::ref это std::refrence_wrapper это именно то, что вам нужно: класс с семантикой значения, который содержит ссылку на ваш исходный объект.


Тот факт, что функторы копируются, отбрасывает множество людей, которые хотят накапливать что-то внутри функтора, а затем удивляются, почему результаты не достигаются. Функтор должен действительно взять ссылка к внешнему объекту. Для остроумия:

Плохой! Не будет работать, как вы ожидаете; функтор может быть скопирован произвольно:

struct Func1 {
int i;
Func1() : i(0) { }
void operator()(T const & x) { /* ... */ }
};

Func1 f;
MyAlgo(myContainer, f);

Хорошо: Вы предоставить аккумулятор; копировать функтор безопасно:

struct Func2 {
int & i;
Func2(int & n) : i(n) { }
void operator()(T const & x) { /* ... */ }
};

int result;
MyAlgo(myContainer, Func2(result));
13

Другие решения

Как сказал Керрек, вы не можете сделать это напрямую:

Но один уровень косвенности и ты в порядке.

struct AbstractFunctor
{
AbstractFunctor( Functor * in_f ): f(in_f) {}
// TODO: Copy constructor etc.

Functor * f;
bool operator()(int a, int b) const { return (*f)(a,b); }
};

int main()
{
vector<int> v;
Functor * mf = new MyFunctor();
sort(v.begin(), v.end(), AbstractFunctor(mf) );
}
5

Как сказали Керрек и Майкл Андерсон, вы не можете сделать это напрямую. Как показывает Майкл, вы можете написать класс-оболочку. Но есть и один в std:: :

sort(v.begin(),
v.end(),
std::bind(&Functor::operator(),
mf,
std::placeholders::_1,
std::placeholders::_2) );
2
По вопросам рекламы [email protected]