0

Consider this simple program:

#include <iostream>

void length(void){
    std::cout<<"My length is void"<<std::endl;
}

void width(void){
    std::cout<<"My width is void"<<std::endl;
}

int main(void){
    std::cout<<"The program length is: "<<length<<std::endl;
    std::cout<<"The program width is: "<<width<<std::endl;
}

The output of this program is:

The program length is: 1
The program width is: 1

What are the numbers that the program prints out, and basically not having much knowledge in C++ particularly, this looks more pythonic syntax to me,and looks as if it should print the function address. I say this because, this problem arose initially while practicing some very basic programs for openGL,

The callback was registered in GLUT with something like:

void line(void){
   //some code for line program ...
}

int main(int argc, char** argv){
    //some more code;
    glutDisplayFunc(line);
    glutMainLoop();
}    

It's almost seeming as if we're passing the address of the function, but, clearly from the above program this is not an address, and the syntax for pointer to function is a bit different, if so, how is this function being registered for callback? And what is it that we're passing to glutDisplayFunc?

and, since I **wanted to register a function that had passed arguments, I search a C++ analogy for python lambda functions, and found similar lambda function, but it didn't work out: **

#include <iostream>

void line(int a,  int b){
//some code that does some plotting  in  the  display window
}

int main(int argc, char** argv){

     auto callback = [](void)->void{
             line(a,b);
           };

     glutDisplayFunc(callback);
     glutMainLoop();
}

This totally fails,the error that is shown is:

no suitable conversion function from "lambda []void ()->void" to "void (*)()" exists   

This was using my python analogy, but what's the solution to this problem? The major parts of confusion are highlighted in bold.

genpfault
  • 51,148
  • 11
  • 85
  • 139
juztcode
  • 1,196
  • 2
  • 21
  • 46
  • In C++ non-member functions naturally decays to pointers to themselves. In this context `line` is equal to `&line`. – Some programmer dude Oct 19 '18 at 13:19
  • 1
    The first half of your question is answered [here](https://stackoverflow.com/questions/17073066/g-calling-a-function-without-parenthesis-not-f-but-f-why-does-it-alwa). I suggest deleting it from your question and just ask why you can't pass the lambda. – NathanOliver Oct 19 '18 at 13:22
  • Lambdas have compiler-generated types that are distinct from all other types - in particular, distinct types from (pointers to) function. Your function is expecting a pointer to a function that accepts no arguments and return `void` (i.e. `void (*)()`). No lambda can have that type. – Peter Oct 19 '18 at 13:22
  • 2
    @Peter But, non capturing lambdas get an implicit conversion operator to a function pointer of their call type. `[](){}` can be implicitly converted to a `void(*)()` – NathanOliver Oct 19 '18 at 13:24
  • Because a pointer to a (non-member) function function can't be converted to `void *`. But it *can* be converted to a `bool`, and the result of that will always be `true` since the pointer is never null. – Some programmer dude Oct 19 '18 at 13:34
  • @Peter, then what's the solution to what I want to do then? – juztcode Oct 19 '18 at 13:34
  • @Someprogrammerdude , yeah got that thanks, Nathan had pointed to me a link to a similar question – juztcode Oct 19 '18 at 13:35
  • @Someprogrammerdude , do you know how should I pass a function to`glutDisplayFunc` that has parameters? – juztcode Oct 19 '18 at 13:35
  • Considering that GLUT will not call the display function with any arguments, you can't. Well you *can* with a little creative casting, but using those arguments will lead to undefined behavior. You can "pass" arguments at compile-time using templates, but there's no way to pass run-time variables. – Some programmer dude Oct 19 '18 at 13:39
  • @niceboy-programmer: "*do you know how should I pass a function toglutDisplayFunc that has parameters?*" That is a completely different question that has nothing to do with what you asked. – Nicol Bolas Oct 19 '18 at 13:40
  • @Someprogrammerdude , how to pass during compile time using templates? – juztcode Oct 19 '18 at 13:53
  • 1
    See e.g. [Passing 1 argument (pointer) to glutDisplayFunc?](https://stackoverflow.com/questions/12299295/passing-1-argument-pointer-to-glutdisplayfunc) – Some programmer dude Oct 19 '18 at 13:57
  • @Someprogrammerdude, Yeah, the third answer there mentions that,but, I do not understand the syntax: `glutDisplayFunc(drawScene<(void *)0>)` . – juztcode Oct 19 '18 at 14:10
  • @niceboy-programmer `nullptr` would have been orders of magnitude better than `(void*)0` there, not to mention much clearer – Lightness Races in Orbit Oct 19 '18 at 15:49

1 Answers1

6

It's almost seeming as if we're passing the address of the function, but, clearly from the above program this is not an address

You've got things backwards. It's not glutDisplayFunc that's doing the weird magical thing; it's std::cout.

Yes, a function name will convert to a function pointer. The combination of operator<< overloads for iostreams and C++ overload resolution rules ultimately leads to << treating functions as if they were boolean values (yes, really). And thus, your << length is equivalent to doing << true.

If you want the address, you can cast the function pointer to a void* before outputting it: << reinterpret_cast<void*>(&length) or the more terse << (void*)&length (though technically this is only conditionally supported by C++, pretty much every real compiler will allow this).

Lastly, in C++, lambdas are not functions; they're objects. You cannot pass an object to something that expects a function pointer. You can convert a capture-less lambda into a function pointer, but you can't do that for one which captures values.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982