2

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?

Chef Gladiator
  • 902
  • 11
  • 23
  • 4
    Just don't use a typedef : `char(*x)(unsigned) = y;`. Though I don't see why this is desirable. This is the same as using `typedef int type; type x = y;` and asking how to achieve that definition in a single line. – François Andrieux Feb 06 '19 at 15:45
  • Type alias (`using`) make for cleaner function pointer type names : `using FP = char(*)(unsigned);`. – François Andrieux Feb 06 '19 at 15:46
  • why not use `std::function` ? – Samer Tufail Feb 06 '19 at 15:47
  • 1
    do you really want to merge the typedef and the variable declaration in one line as Francois interpreted the question? – 463035818_is_not_an_ai Feb 06 '19 at 16:06
  • ...that would explain lots of confusion – 463035818_is_not_an_ai Feb 06 '19 at 16:07
  • Since you're asking about `int x = 21`, then `21` is an integer literal. There's no such thing as a "function literal", so when you do `func_t x = y;` then there's no type of literal that you can use for `y` (except for lambdas in certain cases) – PeterT Feb 06 '19 at 17:05
  • @PeterT for what certain cases there is a literal for lambdas ? – 463035818_is_not_an_ai Feb 06 '19 at 22:16
  • @user463035818 sorry I misspoke, I meant you can coerce lambdas that have an empty capture list to evaluate to a function pointer. They're not a function literal of course. [Answers to this, should cover the details](https://stackoverflow.com/questions/28746744/passing-capturing-lambda-as-function-pointer) – PeterT Feb 06 '19 at 22:21
  • 5
    You could always stick with `auto x = &the_function;'`. – François Andrieux Mar 28 '19 at 14:48
  • 1
    The name of a function pointer variable appears between the return type and the arguments It won't look like `type name = value;`. – François Andrieux Mar 28 '19 at 14:48
  • You're missing the `&` before `whatever`. `FP x = &whatever ;` – perivesta Mar 28 '19 at 14:49
  • 1
    @dave: That's the same for functions, you don't need the ampersand. @emma: Why should that not be possible in C++? This should work fine (except for the `(char)`, which should be `char` in your `typedef`) – andreee Mar 28 '19 at 14:52
  • *"Any ideas?"* is not an answerable question. – IInspectable Jul 01 '21 at 21:51
  • what do you mean with "Author: This of course can not be done. To be deleted." ?!? It is completely fine for questions to ask for something that isnt possible and that answers can then explain a different way to do it. Thats no reason to delete the question. Instead you should accept one of the answers. – 463035818_is_not_an_ai Jul 02 '21 at 09:07

7 Answers7

12

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 1
    Works just as well as in C, and can also be used for array types: `char (*img)[width][3] = malloc(height*sizeof(*img));` While this syntax is pretty useless in C++ (no array types with runtime sizes), it works well in C and sports the same counterintuitive syntax. – cmaster - reinstate monica Mar 28 '19 at 21:09
12

You can use auto:

auto fptr = &f;

It skips the need of a typedef and conserve a nice syntax.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • I like this answer a bit more than the accepted one. It is more C++11-ish even though it is not clear that OP has or wants a C++11 solution. But hey, C++11 is not the "all new exotic" standard any more. – TobiMcNamobi Mar 29 '19 at 07:10
6

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);
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
5

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);

Live Demo

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • btw I still dont understand why you think it would not be possible and imho you should have included a [mcve] together with the error message in the question, though i didnt want to start the same discussion ;) – 463035818_is_not_an_ai Feb 06 '19 at 16:04
  • thanks for your efforts, but this is not an answer, please see my answer. Also max66 has a bit more elegant variant of this, please see his answer too. – Chef Gladiator Feb 07 '19 at 05:25
  • @ChefGladiator "this is not an answer" ?!? I was asking for clarification several times without success, if I was mean I could reply: "This is not a clear question", anyhow you found what you were looking for so everything seems to be fine... – 463035818_is_not_an_ai Feb 07 '19 at 10:20
2

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, "!" );
max66
  • 65,235
  • 10
  • 71
  • 111
  • Almost right, clever and simple .. but this is a two-liner :) – Chef Gladiator Feb 06 '19 at 21:57
  • @ChefGladiator - sorry: I've misunderstood your question; no, I don't think it's possible define a function and, in the same statement, save it in a function-pointer variable without using a lambda (your solution is in a line but, in that sense, you can write a lot of programs in one line). For lambda... I've edited your edit to show how obtain a function pointer using lambda and `auto`. – max66 Feb 07 '19 at 17:57
0

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.

Chef Gladiator
  • 902
  • 11
  • 23
  • 2
    This definition of `one line` seems rather weird. Because by its definition you could just convert any multi-million line program into "one line" by removing all the newlines. – PeterT Feb 07 '19 at 09:14
  • @PeterT do you understand the solution? – Chef Gladiator Feb 07 '19 at 12:59
  • 3
    @ChefGladiator yes, it's exactly the same as the answers of @max66 and @user463035818 . You just removed the newline between the function definition `char foo(unsigned){ return ' '; }` and the pointer declaration/assignment `auto x = foo;`. They're still seperate. Whether you put a newline between them or not doesn't change anything. You can remove all the newlines from your program and it's still the same program – PeterT Feb 07 '19 at 13:22
  • @pet Why did you not vote on this proposed answer then? Do not fear down-voting a contribution (like this one) that's not useful. – IInspectable Jul 01 '21 at 21:48
0

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.

atomsymbol
  • 370
  • 8
  • 11