Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
|
[C++] Function Objects - таки как пользоваться? 08.05.03 16:51 Число просмотров: 1131
Автор: dl <Dmitry Leonov>
|
> Пытался пробиться через дебри STL, но там тот же for_each > принимает > КЛАСС (!) - параметр шаблона которым > собственно и является. (Хотя при использовании for_each я > явно ему параметр не передаю т.е. испльзую как обычную > фунцкию). > Вот так. Кто что скажет?
Ну так и for_each в STL описан не как функция, получающая параметр-указатель на функцию, а как
template<class _InIt, class _Fn1> inline_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func).
_Fn1 превращается в TraveseFuncPtr только при передаче ему указателя на Add7.
|
<programming>
|
[C++] Function Objects - таки как пользоваться? 08.05.03 16:20
Автор: ilushka Статус: Незарегистрированный пользователь
|
Здравствуйте!
Вот собственно вопрос:
У Страусдоха доходчиво вроде в в Параграфе 18.4 его Книги описано как пользоваться Function Objects. И пример работает, и если самому это дело использовать тоже работает нормально. Вот простой пример:
void Add7(int& out_Int)
{
out_Int += 7;
}
class AddNumber
{
public:
int m_iToAdd;
AddNumber(int in_iToAdd = 0)
{
m_iToAdd = in_iToAdd;
}
void operator()(int& out_Int)
{
out_Int += m_iToAdd;
}
};
class A
{
public:
std::vector < int > m_vData;
};
void main()
{
A tmp_a;
tmp_a.m_vData.push_back(7);
tmp_a.m_vData.push_back(5);
tmp_a.m_vData.push_back(6);
std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),Add7);
std::for_each(tmp_a.m_vData.begin(),tmp_a.m_vData.end(),AddNumber(13));
}
---
Но вот как только пытаюсь использовать их сам вот например таким образом:
typedef void (*TraveseFuncPtr) (int&);
void Add7(int& out_Int)
{
out_Int += 7;
}
class AddNumber
{
public:
int m_iToAdd;
AddNumber(int in_iToAdd = 0)
{
m_iToAdd = in_iToAdd;
}
void operator()(int& out_Int)
{
out_Int += m_iToAdd;
}
};
class A
{
public:
std::vector < int > m_vData;
void TraverseVector(TraveseFuncPtr in_func)
{
for (int i = 0; i < m_vData.size(); i++)
{
(*in_func)(m_vData[i]);
}
}
};
void main()
{
A tmp_a;
tmp_a.m_vData.push_back(7);
tmp_a.m_vData.push_back(5);
tmp_a.m_vData.push_back(6);
tmp_a.TraverseVector(Add7); // All ok.
tmp_a.TraverseVector(AddNumber(13)); //C2664
}
---
Сразу получаю облом.
error C2664: 'TraverseVector' : cannot convert parameter 1 from 'class AddNumber' to 'void (__cdecl *)(int &)'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Пытался пробиться через дебри STL, но там тот же for_each принимает
КЛАСС (!) - параметр шаблона которым собственно и является. (Хотя при использовании for_each я явно ему параметр не передаю т.е. испльзую как обычную фунцкию).
Вот так. Кто что скажет?
|
|
[C++] Function Objects - таки как пользоваться? 08.05.03 16:51
Автор: dl <Dmitry Leonov>
|
> Пытался пробиться через дебри STL, но там тот же for_each > принимает > КЛАСС (!) - параметр шаблона которым > собственно и является. (Хотя при использовании for_each я > явно ему параметр не передаю т.е. испльзую как обычную > фунцкию). > Вот так. Кто что скажет?
Ну так и for_each в STL описан не как функция, получающая параметр-указатель на функцию, а как
template<class _InIt, class _Fn1> inline_Fn1 for_each(_InIt _First, _InIt _Last, _Fn1 _Func).
_Fn1 превращается в TraveseFuncPtr только при передаче ему указателя на Add7.
|
|
[C++] Function Objects - таки как пользоваться? 08.05.03 16:48
Автор: amirul <Serge> Статус: The Elderman
|
> Сразу получаю облом. > > error C2664: 'TraverseVector' : cannot convert parameter 1 > from 'class AddNumber' to 'void (__cdecl *)(int &)' > No user-defined-conversion operator available that > can perform this conversion, or the operator cannot be > called Ну да объект-функция все-таки остается объектом. И такое преобразование невозможно (вернее ты его не опредилил). Есть несколько вариантов:
1) Самому перегрузить TraverseVector, чтоб он принимал еще и объекты класса AddNumber
2) Добавить в AddNumber преобразование operator TraveseFuncPtr(), но тогда ты потеряешь параметр
3) ИМХО самый правильный вариант. Поступить как сделано в STL. "Тот же for_each" принимает класс, потому как он может принять ЛЮБОЙ объект, к которому применим operator(). К объекту типа void (*) (int&) он применим (как и к любому указателю на функцию), а в классе AddNumber он перегружен и тоже применим. Поэтому шаблон инстанцируется дважды (короче два разных кода одной функции получается): один раз для указателя и один раз для AddNumber-а. Если кода не сильно много, то можно не заморачиваться с эффективностью и частичной спецификацией шаблонов и сделать следующее:
class A {
public:
std::vector < int > m_vData;
template <class T>
void TraverseVector(T in_func) {
for (int i = 0; i < m_vData.size(); i++)
in_func(m_vData[i]);
}
};
> Пытался пробиться через дебри STL, но там тот же for_each > принимает > КЛАСС (!) - параметр шаблона которым > собственно и является. (Хотя при использовании for_each я > явно ему параметр не передаю т.е. испльзую как обычную > фунцкию). Можно прочитать у того же Страуструпа :-) про выведение типа шаблона. Короче, явно указывать тип параметра шаблона не надо если компилятор сам может его вывести. В частности он может сделать это по агрументам шаблонной функции.
> > Вот так. Кто что скажет?
|
| |
[C++] Function Objects - таки как пользоваться? 10.05.03 10:10
Автор: ilushka Статус: Незарегистрированный пользователь
|
Спасибо большое все понял ;)
|
|
[C++] Функтор (functional object) и указатель на функцию - не одно и то же, если не использовать шаблон 08.05.03 16:48
Автор: Ktirf <Æ Rusakov> Статус: Elderman Отредактировано 08.05.03 16:52 Количество правок: 2
|
Элементарно, Ватсон. Вы сначала объявляете TraverseFuncPtr как указатель на функцию:
typedef void (*TraveseFuncPtr) (int&);
---
и A::TraverseVector как принимающий этот указатель параметром:
> class A
> {
> public:
> std::vector < int > m_vData;
> void TraverseVector(TraveseFuncPtr in_func)
> {
> for (int i = 0; i < m_vData.size(); i++)
> {
> (*in_func)(m_vData[i]);
> }
> }
> };
---
но после этого вы пытаетесь подсунуть вместо указателя на функцию что-то совершенно другое - объект, не имеющий неявного приведения к TraverseFuncPtr:
tmp_a.TraverseVector(AddNumber(13)); //C2664
---
Естественно, компилятор обижается.
> Пытался пробиться через дебри STL, но там тот же for_each > принимает > КЛАСС (!) - параметр шаблона которым > собственно и является. (Хотя при использовании for_each я > явно ему параметр не передаю т.е. испльзую как обычную > фунцкию). Не дайте себя запутать. Параметром шаблона может быть ЛЮБОЙ ТИП, хоть int. Правда, внутри for_each стоит вызов этого самого шаблонного "объекта" со скобками, в результате возможные варианты ограничиваются указателем на функцию либо объектом имеющим operator() (больше ничего такой синтаксис не переварит).
Итого. Если вы хотите передавать и указатели на функции, и функторы, у вас два варианта:
1) TraverseVector принимает на входе объект unary_function или binary_function (внимание - не по значению! иначе произойдет срезка типа). Функторы наследуются от unary_functin/binary_function. Указатели на функции при передаче обертываются в unary_function/binary_function (см. ptr_fun у Страуструпа)
2) TraverseVector объявляется шаблоном и на принимает параметр с шаблонным типом. Тогда он ничем по способу работы с параметрами не будет отличаться от for_each.
Есть еще и третий вариант:
3) Не использовать TraverseVector, а выкрутиться через for_each и чуть более сложный функтор, который будет, например, другом класса A. Идеологически это более правильно, особенно если есть возможность обойтись без дружественных отношений классов.
|
| |
[C++] Функтор (functional object) и указатель на функцию - не одно и то же, если не использовать шаблон 10.05.03 10:14
Автор: ilushka Статус: Незарегистрированный пользователь
|
Тоже все понял, спасибо ;)
|
| | |
Пожалуйста :) Тогда нажми "закрыть" на корневом посте 11.05.03 12:21
Автор: Ktirf <Æ Rusakov> Статус: Elderman
|
|
|
|