Reputation: 1008
Author: This of course can not be done. Learn from the answers below.
In C++ how do we do the following
// fundamental language construct
type name = value ;
// for example
int x = y;
with function pointers?
typedef (char)(*FP)(unsigned);
// AFAIK not possible in C++
FP x = y ;
I can use lambdas:
FP x = []( unsigned k) -> char { return char(k); }
But I do not know how to do this without the lambda. Any ideas?
Upvotes: 2
Views: 1302
Reputation: 421
The code:
typedef char(*FP)(int);
FP x = y;
fails to compile with current C++ compilers if y
is a lambda expression capturing a variable.
// Compiles OK
FP x0 = [](int k) -> char { return char(k); };
// Fails to compile
int i = 123;
FP x1 = [=](int k) -> char { return char(k); };
FP x2 = [=](int k) -> char { return char(k+i); };
FP x3 = [&](int k) -> char { return char(k+i); };
FP x4 = [i](int k) -> char { return char(k+i); };
// error: cannot convert ‘main()::<lambda(int)>’ to ‘FP {aka char (*)(int)}’
// in initialization
The reason why it fails to compile is that the size of the right side of the assignment to x1
...x4
is greater than size of FP
.
For a C++ compiler to make assignments to x1
...x4
be valid it would need to generate code at runtime. Current C++ compilers such as GCC and clang do not support this, mainly because it would cause memory leaks because C++ isn't a garbage collected language. Some garbage collected language implementations, such as earlier versions of the official Go compiler, do support such assignments by performing runtime code generation.
Upvotes: 0
Reputation: 41770
You can use auto
:
auto fptr = &f;
It skips the need of a typedef and conserve a nice syntax.
Upvotes: 12
Reputation: 120011
Whenever you can write a typedef, you can also write a variable declaration with no typedef, with almost identical syntax.
Example:
// typedef
typedef char(*FP)(unsigned);
FP x = y ;
// no typedef
char(*x)(unsigned) = y;
Remove the typedef
keyword, and you have a variable declaration. Slap an initialisation on it if you want.
Upvotes: 12
Reputation: 66230
Well... if you're using lambdas, you can also use auto
, so
auto x = foo;
The following is a full compiling example with a static_assert()
that verify the obtained type
#include <type_traits>
char foo (unsigned)
{ return ' '; }
int main ()
{
auto x = foo;
static_assert( std::is_same<decltype(x), char(*)(unsigned)>::value, "!" );
}
Using auto
with lambda in the way you used it with FP
auto y = []() ->bool { return true; };
leads to something different: the type of y
above is an unnamed class with an operator()
, not a function pointer type to that operator()
.
If you want a pointer to function, you have to convert the lambda to it using the operator +
, as you can verify with the following static_assert()
auto y = +[]() ->bool { return true; };
static_assert( std::is_same<decltype(y), bool(*)()>::value, "!" );
Upvotes: 2
Reputation: 1008
Many thanks all for the lively roller-coaster of useful comments. Somebody on Reddit, where I asked the same question, under the user name "TheTiefMaster", dropped this "one liner":
// also works as C
char whatever(unsigned k) { return char(k); } char(*F)(unsigned) = whatever;
Let me clarify: I do understand these are two statements on one line. And no there is no type in here, but one function pointer pointing to the same function. The usage:
auto x = whatever(65); // 'A'
auto y = F(66); // 'B'
Then I figured the following will make the function definition and its type declaration:
// FP is a type of function whoever
char whoever(unsigned k) { return 'A'; } typedef char(*FP)(unsigned) ;
Calling whoever behaves as expected
auto w = whoever(42) ; // 'A'
FP is where it starts getting interesting. FP is a type, and as it turns out one can cast to the type.
// using FP as a type
// c++ style type cast
// empty cast returns nullptr
auto fun = FP();
// calling fun() above crashes
// but it is "invocable" as per C++ rules
static_assert(std::is_invocable_v<P2F()>);
Passing any argument to this cast, works and returns non null address:
// update: this compiles only on MSVC
// and is a bug
auto fun = FP(42);
// type of fun is char (*) (unsigned)
Calling the result of this fun crashes, obviously:
// reading access violation
fun(123) ;
This cast with an instance from any required function, works:
auto fun = FP(whatever);
// works, obviously
fun(65) ; // 'A'
To use this knowledge we will use the static_cast to safely cast to what we can call. C++ type cast is too forceful, just like C style type cast is.
// does not compile
// fun is the wrong type and can not be called
auto fun = static_cast<FP>(42);
// does compile, fun is safe to call
auto fun = static_cast<FP>(whatever);
// works, obviously
fun(65) ; // 'A'
This investigation is obviously far from over. I shall proceed with it, elsewhere.
Update:
using FP = char (*)(int) ;
// must not compile, compiles under MSVC
auto oops = FP(42) ;
Is the bug in MSVC, I reported it today.
Upvotes: 0
Reputation: 122724
But I do not know how to do this without lambda. Any ideas?
Just dont use a lambda but a function:
typedef char(*FP)(unsigned);
char foo(unsigned){ return 0;}
int main() {
FP x = foo;
}
Function pointer typedefs are rather nasty, if you can better use using
:
using FP = char(*)(unsigned);
Upvotes: 5
Reputation: 48287
It is almost the same as Lambdas, but hard to read i think:
void my_int_func(int x)
{
std::cout << "ther param is: " << x << std::endl;
}
//
int main(int argc, char *argv[])
{
void (*foo)(int) = my_int_func;
foo(1);
Upvotes: 6