Reputation: 11753
I have a question related to function objects or functors in C++. I understand that function objects can substitute function pointers in many cases, such as some algorithms in STL. However, I do not know how to invoke function object if the function's argument is function pointer. For example:
class ClassA
{
public:
void operator()(std::string &name)
{
std::cout<<"Class A"<<std::endl;
}
};
class ClassB
{
public:
void operator()(std::string &name)
{
std::cout<<"Class B"<<std::endl;
}
};
void testClass(void(*fun)(std::string&), std::string &name )
{
(*fun)(name);
}
void funClass(std::string &str)
{
std::cout<<"hello C "<<str<<std::endl;
}
It is very easy to invoke the testClass
function if I only use function pointer:
std::string str= "hello.txt";
testClass(funClass,str);
However, I donot know how to invoke testClass if I want to use function object.
ClassA obj;
testClass(obj.operator()(str),str); // compilation errors
Upvotes: 1
Views: 155
Reputation: 146910
You can also use a thread-local stack of function objects. This would be something like
template<typename Sig> struct horrible_hackery;
template<typename Ret, typename... Args> struct horrible_hackery {
static thread_local std::stack<std::function<Ret(Args...)>> functions;
static Ret trampoline_callback(Args... args) {
return functions.top()(args...);
}
template<typename F, typename Around> static void execute_around_fptr(F f, Around a) {
functions.push(f);
a(&trampoline_callback);
functions.pop();
}
};
Now you can use
ClassA obj;
horrible_hackery<void(std::string&)>::execute_around(obj, [&](void(*fptr)(std::string&)) {
return testclass(fptr, str);
});
There is a C++03 version of this which is even more terrible terrible hackery that you don't want to think about.
If you're truly desperate for this feature and you can't accept the purely stack-based solution above, you can download a JIT compiler for the platform of your choice like LLVM and then JIT a thunk for yourself. This is pretty extreme though.
However, these limitations and generally horrible hackery leads one to the following conclusions:
Upvotes: 0
Reputation: 31435
A "functor" class is not a function pointer. However std::function
takes constructors that will implicitly create one from a functor or function pointer.
If you are allowed to modify testClass then ideally make it more generic:
void testClass( std::function< void( std::string & ) > func, std::string & name )
{
func( name );
}
You can then call
testClass( ClassA(), name );
If it is not going to modify the string it should probably take this parameter by const reference.
You could write delegate functions for your classes that forward them like this but I don't think that's really what you are looking for as you'd have to write one for each delegate:
Otherwise you can write a templated function like this
template< typename T >
void callT( std::string & name )
{
T t;
t( name );
}
testClass( callT< ClassA > );
If you are using C++11
you can pass in a lambda function in your instance which will convert to a function pointer. (Thanks Steve Jessop for telling me this).
In this case it is a bit of a workaround as you would have to type out the lambda function for every functor class you want to use it with. (So even though the feature is there the template is possibly better).
To do it with the lambda you would do
testClass( []( std::string & str ){ ClassA a; a(str); }, name );
Note that for the lambda to be able to convert to a function it cannot take captchas, but then it wouldn't be possible to do the templated version if you needed extra data members either.
Upvotes: 2
Reputation: 2965
Rewrite the testClass
function as a function template.
template<typename T>
void testClass(T fun, std::string& name) {
fun(name);
}
Then it can accept function pointers as well as instances of function objects.
That's simpler than triggering the std::function
machinery.
There is this flexibility in C++ function pointers where you're not forced to write *fun()
to call the pointed-to function. You can just write fun()
.
And by the way, you can also pass in references-to-functions.
Upvotes: 0
Reputation: 145239
A class instance is in general not a function pointer, but a class instance that is a lambda which does not capture anything, converts implicitly to function pointer:
auto const f = []( std::string& s ) { classA()( s ); };
testClass( f, "blah" );
Or use an ordinary named function.
Standard library algorithms can use either raw function pointer or class instance with operator()
, because the type is templated.
The more general question, how to convert a possibly stateful functor object to raw function pointer, e.g. for C callback, is more interesting.
The standard library unfortunately lacks support for that.
Upvotes: 1