Недавно потребовалось передать функтор туда, где ожидается указатель на функцию. Удивительно, но сходу не получается. Оказывается, именем объекта функтора нельзя инициализировать указатель на функцию, несмотря на полностью совпадающие типы возврата и списки формальных параметров.
Прямых указаний в интернете по запросам содержащим "функтор" и "указатель на функцию" найти не удалось, хотя информации и по функторам и по указателям достаточно много. Наиболее близкой для решения задачи, мне показалась информация от AlenaCpp:
http://alenacpp.blogspot.com/2... -post.html
Там при упоминании функторов есть вот такой шаблончик
| C++ | 1
2
3
4
5
6
7
| template <class Fun>
void foo(Fun f)
{
//...
f();
//...
} |
|
| Продемонстрировать результат моих размышлений на простом и искусственном (надуманном) примере можно бы так:
| 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
| #include <iostream>
using namespace std;
struct Call_back_class
{
int a;
int b;
Call_back_class(int a_, int b_)
:a(a_), b(b_)
{}
Call_back_class(const Call_back_class &rhs)
:a(rhs.a), b(rhs.b), calc_result(rhs.calc_result)
{}
int (*calc_result)(Call_back_class &);
int calc(){return (*calc_result)(*this);}
};
template< typename Arg, typename T>
int foo(Arg &n)
{
T f;
return f(n);
}
int main(int argc, char* argv[])
{
Call_back_class cb(123, 456);
struct Plus
{
int operator()(const Call_back_class &cbck_){ return cbck_.a + cbck_.b ;}
};
int (*calc_result)(Call_back_class &) = foo<Call_back_class, Plus>;
cb.calc_result=calc_result;
cout<<cb.calc()<<endl;//579
cout<<endl;
struct Minus
{
int operator()(const Call_back_class &cbck_){ return cbck_.a - cbck_.b ;}
};
cb.calc_result= foo<Call_back_class, Minus>;
cout<<cb.calc()<<endl;//-ззз
cout<<endl;
struct Multiply
{
int operator()(const Call_back_class &cbck_){ return cbck_.a * cbck_.b ;}
};
cb.calc_result= foo<Call_back_class, Multiply>;
cout<<cb.calc()<<endl;//56088
cout<<endl;
system("pause");
return 0;
} |
|

Указатели на функции, построенные как шаблонные обёртки функторов, могут пригодиться не только для реализации обратных вызовов. Вот что удалось выяснить, в случае использования функтора, как предиката (один из самых частых вариантов).
Вот тут, я нашёл интересный пример с размышлением о том, как дорого по производительности может обойтись функтор-предикат, переданный алгоритму сортировки.
https://habrahabr.ru/post/234215/
Речь идёт о конструировании объектов. Вывод о том, что на каждый акт сравнения запускается полтора конструктора не радует.
Однако применив фокус с указателем на функцию запускающую функтор можно сократить количество конструкторов на треть. А если усовершенствовать шаблон снабдив его статическим объектом функтора, то потребуется всего один конструктор независимо от количества сравнений(!!):
| 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
| #include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Compare
{
public:
Compare()
{
cout<<"Compare::Compare()"<<endl;
}
Compare(const Compare& compare)
{
cout<<"Compare::Compare(const Compare& )"<<endl;
}
~Compare()
{
cout<<"Compare::~Compare()"<<endl;
}
bool operator() (int v1, int v2)
{
cout<<"compare "<<v1<<" "<<v2<<endl;
return v1 < v2;
}
};
template< typename Arg, typename T>
bool foo(Arg m, Arg n )
{
T f;
return f(m, n);
}
template< typename Arg, typename T>
bool fo(Arg m, Arg n )
{
static T f=T();
return f(m, n);
}
int main()
{
vector<int> mas;
for( int k = 0; k <= 3; k++ )
mas.push_back( rand() );
for( int k = 0; k <= 3; k++ )cout << mas[k]<<" ";
cout << endl;
//sort( mas.begin(), mas.end(), Compare() );//раскомментируйте этот кошмар...
//11 конструкторов и деструкторов
//bool (*comp)(int, int)= foo<int, Compare>;//это немного лучше -
//sort( mas.begin(), mas.end(), *comp );//8 шт. - на каждое сравнение по одному конструктору/деструктору
bool (*cmp)(int, int)= fo<int, Compare>;//а тут всего один конструктор! :)
sort( mas.begin(), mas.end(), *cmp );
for( int k = 0; k <= 3; k++ )cout << mas[k]<<" ";
cout << endl;
system("pause");
return 0;
} |
|
раскомментируйте закоментированные фрагменты по очереди, закомментировав остальные и посмотрите разницу.
|