Function Pointers and their type?

I understand function objects, but im having a bit of difficulty on how functions pointers work, especially when passed to templated functions (like those in the <algorithms> library).

Here is an example of a code I dont fully understand:

Implementation of find_if function
1
2
3
4
5
6
7
8
9
template<class InputIterator, class UnaryPredicate>
InputIterator find_if (InputIterator first, InputIterator last, UnaryPredicate pred)
{
  while (first!=last) {
    if (pred(*first)) return first;
    ++first;
  }
  return last;
}


using the find_if function:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// find_if example
#include <iostream>     // std::cout
#include <algorithm>    // std::find_if
#include <vector>       // std::vector

bool IsOdd (int i) {
  return ((i%2)==1);
}

int main () {
  std::vector<int> myvector;

  myvector.push_back(10);
  myvector.push_back(25);
  myvector.push_back(40);
  myvector.push_back(55);

  std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
  std::cout << "The first odd value is " << *it << '\n';

  return 0;
}


Here's how I understand these two pieces of code. Please correct me if im wrong.

Now I know that isOdd the way its used in line 18 (of the second code) is a function pointer. In other words, isOdd is a pointer pointing to the function isOdd. And according to learncpp.com, the name of every function is actually a pointer to itself, correct?

So this pointer gets passed to the find_if function. The pointer to function is used on line 5, but more importantly, it is implicitly being dereferenced when this happens. In other words:

if (pred(*first)) return first; and if ((*pred)(*first)) return first; are exactly equivalent, correct?

My only question is, what is the type of this pointer when its passed to the templated find_if function. In other words, what type replaces "UnaryPredicate"?
Last edited on
Hi,

http://en.cppreference.com/w/cpp/algorithm/find

p - unary predicate which returns ​true for the required element.

The signature of the predicate function should be equivalent to the following:

bool pred(const Type &a);

The signature does not need to have const &, but the function must not modify the objects passed to it.
The type Type must be such that an object of type InputIt can be dereferenced and then implicitly converted to Type. ​


http://en.cppreference.com/w/cpp/concept/Predicate

The Predicate link has exactly what you had :+) if (pred(*first)) {...}
are exactly equivalent, correct?


The Predicate concept describes a function object that takes a single iterator argument that is dereferenced and used to return a value testable as a bool.

Which is what you were saying too :+)

In other words, what type replaces "UnaryPredicate"?


http://en.cppreference.com/w/cpp/concept/FunctionObject

Regards :+)

> the name of every function is actually a pointer to itself, correct?

No.

With bool IsOdd (int i ) { /* ... */ },

IsOdd is an lvalue of type bool(int) (function type)

There is an implicit conversion from an lvalue of function type T to a prvalue of 'pointer to function of type T'

1
2
3
4
5
6
7
using function_type = bool(int) ; // type of the function

function_type& reference_to_function = IsOdd ; // reference to function
function_type* pointer_to_function = &IsOdd ; // pointer to function

pointer_to_function = IsOdd ; // implicit conversion from function to pointer to function
pointer_to_function = reference_to_function ; // implicit conversion from function to pointer to function 



> if (pred(*first)) return first; and if ((*pred)(*first)) return first; are exactly equivalent, correct?

Yes, if the type of pred is 'pointer to function'
In this case, (*pred) is an lvalue expression that refers to the function

Built-in function call operator

A function call expression, such as E(A1, A2, A3), consists of an expression that names the function, E, followed by a possibly empty list of expressions A1, A2, A3, ..., in parentheses.

The expression that names the function can be
a) lvalue expression that refers to a function
b) pointer to function
c) explicit class member access expression that selects a member function
d) implicit class member access expression, e.g. member function name used within another member function.
http://en.cppreference.com/w/cpp/language/operator_other#Built-in_function_call_operator



> In other words, what type replaces "UnaryPredicate"?

The type bool(*)(int) ie. pointer to function of type bool(int)
Last edited on
Excellent, im understanding this better now. Just a few follow-ups:

@JLBorges:
No.

Okay, so can you explain what the author meant here?: http://www.learncpp.com/cpp-tutorial/78-function-pointers/

Im referring to this specific quote from the link:

Identifier foo is the function’s name. But what type and value does foo have? It turns out that foo is actually a constant pointer to a function that takes no parameters and returns an integer. Function pointer foo holds (points to) the address in memory where the code for function foo starts.


and this:

As you can see, the implicit dereference method looks just like a normal function call -- which is what you’d expect, since normal function names are pointers to functions anyway!


There is an implicit conversion from an lvalue of function type T to a prvalue of 'pointer to function of type T'


So this implicit conversion happens when isOdd is passed to the find_if function? Meaning, isOdd is passed as a reference to the function, but when it becomes 'pred', it becomes a pointer to the isOdd function?

Lastly, some questions about the code you wrote:

(a) So line 4 and 6 are the same? In both cases, you are assigning the address of isOdd to a function pointer. The address operator is optional:

1
2
3
void f(int);
void (*p1)(int) = &f;
void (*p2)(int) = f; // same as &f 


http://en.cppreference.com/w/cpp/language/pointer#Pointers_to_functions

So that why the address operator is optional, the conversion from 'reference to function' to 'pointer to function' happens implicitly in an assignment statement.

Correct me if im wrong here.

(b) Just a syntax question: Can line 4 be rewritten like this:
bool(*ptr_to_function)(int) = &isOdd ?
and also like this: bool(*)(int) ptr_to_function = &isOdd ?

Im sorry for some many questions. Im just trying to get a thorough understanding of this topic.
Last edited on
> Im referring to this specific quote from the link

>> Identifier foo is the function’s name.
Yes.

>> It turns out that foo is actually a constant pointer to a function ...
No.

>> Function pointer foo holds (points to) ....
foo is not a pointer to a function.

>> since normal function names are pointers to functions anyway!
No.


> So this implicit conversion happens when isOdd is passed to the find_if function?
> Meaning, isOdd is passed as a reference to the function, but when it becomes 'pred',
> it becomes a pointer to the isOdd function?

Yes.
The type of isOdd is function (not reference to function).
The argument isOdd is evaluated as an expression (the type of an expression is always a non-reference-type). Its value category is lvalue.

Where P is the template type-parameter and A is the type of the argument:
1
2
3
4
5
Before deduction begins, the following adjustments to P and A are made:
1) If P is not a reference type,
    a) if A is an array type, A is replaced by the pointer type obtained from array-to-pointer conversion;
    b) otherwise, if A is a function type, A is replaced by the pointer type obtained from function-to-pointer conversion;
    c) otherwise, if A is a cv-qualified type, the top-level cv-qualifiers are ignored for deduction

http://en.cppreference.com/w/cpp/language/template_argument_deduction



> the conversion from 'reference to function' to 'pointer to function' happens implicitly in an assignment statement.

Yes. The implicit conversion is from an lvalue of type function to a prvalue of type pointer-to-function. (The right hand side of the assignment is evaluated as an expression.)

Implicit function-to-pointer conversion could also happen in other contexts where a pointer to function is expected, and the expression evaluates to an lvalue of type function.


> Just a syntax question: Can line 4 be rewritten like this: bool(*ptr_to_function)(int) = &isOdd; ?
Yes.

> and also like this: bool(*)(int) ptr_to_function = &isOdd; ?
No. (Because C does not allow it.)
Last edited on
Ah, you are tremendously helpful.

So by the way, should I stop using learncpp.com as a reference? The website has helped me out in the past, but it seems he is blatantly wrong in this case.
Why does this print 1 in all cases?:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

int foo()
{
    return 5;
}

int main()
{
    std::cout << foo << std::endl;
    std::cout << &foo << std::endl;

    int(*ptr_to_function)() = foo;
    std::cout << ptr_to_function << std::endl;
    std::cout << *ptr_to_function << std::endl;
}


I was expecting addresses in hexadecimal.
Last edited on
I'm completely unfamiliar with learncpp.com.

I suppose you could continue to use learncpp.com as a resource for tutorials, but don't use it as a reference.
Once you have read a tutorial there, or as you read a tutorial there, validate what is says with the reference in cppreference.com
http://en.cppreference.com/w/cpp/language
Gotcha.

Any idea about my last post?
> Why does this print 1 in all cases?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>

struct A
{
    int mf( int a ) { return m += a ; }
    int m = 0 ;
};

int fn( int a ) { return a*2 ; }

int main()
{
    A a ;

    std::cout << "\n-------------- a. pointer to object ----------------\n\n" ;
    // a. pointer to object (T* where T is an object type)

    auto pa = std::addressof(a) ; // pointer to A
    bool b = pa ; // implicit conversion pointer to bool
    void* pv = pa ; // implicit conversion to 'pointer to void'

    // *pv ; // *** error: pv is not a 'pointer to object'

    std::cout << pv << '\n' ; // ostream::operator<< ( const void* )
    std::cout << pa << '\n' ; // implicit conversion from 'pointer to A' to 'pointer to const void'


    std::cout << "\n-------------- b. pointer to function ----------------\n\n" ;
    // b. pointer to function (F* where F is a non-member or static member function)

    using fn_type = int(int) ;
    fn_type* pfn = &fn ; // pointer to function
    pfn = fn ; // implicit conversion: 'function' to 'pointer to function'
    b = pfn ; // implicit conversion: 'pointer to function' to bool
    // pv = pfn ; // *** error: type of pfn is not a pointer to object type

    auto& rfn = *pfn ; // dereference (unary * operator): type of rfn is 'reference to function'
    b = rfn ; // implicit conversion: 'function' to 'pointer to function'
              //                      'pointer to function' to 'bool'

    std::cout << b << '\n' ; // ostream::operator<< ( bool )
    std::cout << pfn << '\n' ; // implicit conversion from 'pointer to function' to 'bool' (true)

    std::cout << fn << '\n' ; // implicit conversion: 'function' to 'pointer to function'
                              //                      'pointer to function' to 'bool'
    std::cout << std::boolalpha << pfn << '\n' ; // implicit conversion from 'pointer to function' to 'bool' (true)

    pfn = nullptr ;
    std::cout << pfn << '\n' ; // implicit conversion from 'pointer to function' to 'bool' (false)

    if(pfn) {} // 'pointer to function' contextually converted to 'bool'
    if(!rfn) {} // implicit conversion: 'function' to 'pointer to function',
                // 'pointer to function' contextually converted to 'bool'


    std::cout << "\n-------------- c. pointer to member  ----------------\n\n" ;
    // c. pointer to member T::*m (where T is a class type)

    auto pmo = &A::m ; // pointer to member object
    auto pmf = &A::mf ; // pointer to member function

    // *pmf ; // *** error: type of pmf is not a pointer to object type
    // pv = pmf ; // *** error: type of pmf is not a pointer to object type

    b = pmf ; // implicit conversion to bool
    std::cout << b << '\n' ; // ostream::operator<< ( bool )
    std::cout << pmf << '\n' ; // implicit conversion from 'pointer to member function' to 'bool'

    // pointer to member operators .* ->*
    a.*pmo = 7 ;
    (pa->*pmf)(23) ;
}

-------- clang++/libc++ ------------

main.cpp:43:18: warning: address of function 'fn' will always evaluate to 'true' [-Wpointer-bool-conversion]
    std::cout << fn << '\n' ; // implicit conversion: 'function' to 'pointer to function'
              ~~ ^~
main.cpp:43:18: note: prefix with the address-of operator to silence this warning
    std::cout << fn << '\n' ; // implicit conversion: 'function' to 'pointer to function'
                 ^
                 &
1 warning generated.

-------------- a. pointer to object ----------------

0x7fffea2fa960
0x7fffea2fa960

-------------- b. pointer to function ----------------

1
1
1
true
false

-------------- c. pointer to member  ----------------

true
true

--------- g++/libstdc++ ------------

main.cpp: In function 'int main()':
main.cpp:37:9: warning: the compiler can assume that the address of 'rfn' will always evaluate to 'true' [-Waddress]
     b = rfn ; // implicit conversion: 'function' to 'pointer to function'
         ^~~
main.cpp:37:9: warning: the compiler can assume that the address of 'rfn' will always evaluate to 'true' [-Waddress]
main.cpp:43:18: warning: the address of 'int fn(int)' will always evaluate as 'true' [-Waddress]
     std::cout << fn << '\n' ; // implicit conversion: 'function' to 'pointer to function'
                  ^~
main.cpp:51:9: warning: the compiler can assume that the address of 'rfn' will always evaluate to 'true' [-Waddress]
     if(!rfn) {} // implicit conversion: 'function' to 'pointer to function',
         ^~~
main.cpp:51:9: warning: the compiler can assume that the address of 'rfn' will always evaluate to 'true' [-Waddress]

-------------- a. pointer to object ----------------

0x7fff1f3d6900
0x7fff1f3d6900

-------------- b. pointer to function ----------------

1
1
1
true
false

-------------- c. pointer to member  ----------------

true
true

http://coliru.stacked-crooked.com/a/f3f3b5066b18f1b6
Why does this print 1 in all cases?:


In function 'int main()':
10:18: warning: the address of 'int foo()' will always evaluate as 'true' [-Waddress]
11:19: warning: the address of 'int foo()' will always evaluate as 'true' [-Waddress]


Just my 2 cents here :+)

Did you get the warnings? If not, you probably need to compile with more warning options. With gcc this warning is enabled by -Wall, not sure what that is under VS.

Two things: had you seen the warnings there would perhaps be a question about them; Make the compiler work for you, get it to tell you about these things :+)

Note I wouldn't have known why either, but at least there is a clue in the warning to investigate. Fortunately we have awesome guru's like JLBorges et al to shine a very bright light on these things :+)

@JLBorges: Thanks for the self-explanatory and clear program. I understand now, the pointers-to-functions are ultimately converted to booleans. They will always be evaluated as false unless they are null pointers.

@TheIdeasMan: I missed the warnings because I did build and run altogether, and so the warnings disappeared when the program ran. This time I only built the program, and indeed I did get those warnings. Thanks.
Topic archived. No new replies allowed.