Можно ли упростить / улучшить следующую передачу указателя на функцию с помощью boost :: function и / или boost :: bind?
void PassPtr(int (*pt2Func)(float, std::string, std::string))
{
int result = (*pt2Func)(12, "a", "b"); // call using function pointer
cout << result << endl;
}
// execute example code
void Pass_A_Function_Pointer()
{
PassPtr(&DoIt);
}
Ты можешь использовать boost::function<>
чтобы сделать возможным использование различных типов вызываемых объектов в качестве входных данных функции.
Ниже приведен пример использования C ++ 11 (см. Примечания после этого примера). Вот как бы вы переписали свою функцию:
#include <functional>
#include <string>
#include <iostream>
void PassFxn(std::function<int(float, std::string, std::string)> func)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
int result = func(12, "a", "b"); // call using function object
std::cout << result << std::endl;
}
Это пара функций для тестирования:
int DoIt(float f, std::string s1, std::string s2)
{
std::cout << f << ", " << s1 << ", " << s2 << std::endl;
return 0;
}
int DoItWithFourArgs(float f, std::string s1, std::string s2, bool b)
{
std::cout << f << ", " << s1 << ", " << s2 << ", " << b << std::endl;
return 0;
}
struct X
{
int MemberDoIt(float f, std::string s1, std::string s2)
{
std::cout << "Member: " << f << ", " << s1 << ", " << s2 << std::endl;
return 0;
}
static int StaticMemberDoIt(float f, std::string s1, std::string s2)
{
std::cout << "Static: " << f << ", " << s1 << ", " << s2 << std::endl;
return 0;
}
};
А вот и тестовая процедура:
int main()
{
PassFxn(DoIt); // Pass a function pointer...
// But we're not limited to function pointers with std::function<>...
auto lambda = [] (float, std::string, std::string) -> int
{
std::cout << "Hiho!" << std::endl;
return 42;
};
PassFxn(lambda); // Pass a lambda...
using namespace std::placeholders;
PassFxn(std::bind(DoItWithFourArgs, _1, _2, _3, true)); // Pass bound fxn
X x;
PassFxn(std::bind(&X::MemberDoIt, x, _1, _2, _3)); // Use a member function!
// Or, if you have a *static* member function...
PassFxn(&X::StaticMemberDoIt);
// ...and you can basically pass any callable object!
}
И вот живой пример.
ВЫСТУПЛЕНИЯ:
Вы можете легко изменить std::function<>
в boost::function<>
а также std::bind<>
в boost::bind<>
если вы работаете с C ++ 03 (на самом деле, Boost.Function является то, что вдохновило std::function<>
а позже стал частью стандартной библиотеки C ++). В этом случае вместо включения <functional>
заголовок, вам нужно будет включить boost/function.hpp
а также boost/bind.hpp
заголовки (последний, только если вы хотите использовать boost::bind
).
Для дальнейшего примера, который должен дать вам ощущение силы, std::function<>
/ boost::function<>
дает вам возможность инкапсулировать любой вызываемый объект, также смотрите этот вопрос&А на StackOverflow.
Я предполагаю, что вы хотите улучшить функциональность PassPtr
, а не весь пример кода, который вы дали. Если вы используете C ++ 11 и можете использовать лямбда-выражения, я бы упростил это до:
template <typename Func>
void PassPtr(Func f) {
std::cout << f(12, "a", "b") << std::endl;
}
Это позволит любому вызываемому объекту быть переданным как f
, Причина, по которой функция берется из выведенного типа шаблона, заключается в том, что любые передаваемые лямбда-выражения должны быть встроены. Конечно, это не приводит к наложению какой-либо конкретной подписи на переданную функцию (или на то, что это должен быть даже вызываемый объект). Например, если вы передаете int
вы получите некоторые запутанные ошибки компилятора.
Альтернатива, использующая [boost|std]::function
, это сделать это:
void PassPtr(std::function<int(float, std::string, std::string)> f) {
std::cout << f(12, "a", "b") << std::endl;
}
Это позволит передавать любой вызываемый объект, как указано выше, но, вероятно, не приведет к тому, что лямбда-выражения будут встроены.