how does argument get passed to function name

Aug 22, 2022 at 11:25am
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


#include <iostream>
#include <array>
#include <algorithm>
#include <iterator>
using namespace std;

void timesTwo(int i)
{
    cout << i * 2 << " ";
}

int main()
{
    const size_t SIZE{4}; //size of array values
    array<int, SIZE> values {1, 2, 3, 4};


    //output each element multipled by two
    for_each(values.cbegin(), values.cend(), timesTwo);
}



timesTwo is a function that takes in an int argument then multiply by two and prints the argument out.
values is an int vector.


How does for_each pass the argument to timesTwo since timesTwo is just a function name?
Last edited on Aug 22, 2022 at 11:31am
Aug 22, 2022 at 11:33am
The third argument of for_each() is not just a function name (string). It has type UnaryFunction!

So, you are in fact passing a function object (effectively a pointer to your timesTwo() function) into the for_each() function.

1
2
template<class InputIt, class UnaryFunction>
UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);

[...]
f - function object, to be applied to the result of dereferencing every iterator in the range [first, last)
The signature of the function should be equivalent to the following:
void fun(const Type &a);
Last edited on Aug 22, 2022 at 11:40am
Aug 22, 2022 at 11:35am
It gets passed as a function pointer or a function object (which, I suspect, in practice means passing some sort of pointer).

BTW, you will confuse a lot of people if you call it "timesTwo" but use it to multiply by ... FIVE! (Which you've now edited! Boom!)
Last edited on Aug 22, 2022 at 11:36am
Aug 22, 2022 at 11:43am
@kigar64551
Do you mind elaborating further?
how is the timesTwo() function a function object?
Aug 22, 2022 at 11:48am
In C/C++, you can pass pointers to functions. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef void (*FunctionPtr)(int);

void timesTwo(int i)
{
    std::cout << i * 2 << " ";
}

void foo(FunctionPtr func, int arg)
{
    func(arg);
}


int main(void)
{
    foo(timesTwo, 42);
}

Note: Function name without parenthesis takes the address of the function, rather than invoking the function (cf. line #16).
Last edited on Aug 22, 2022 at 11:51am
Aug 22, 2022 at 11:51am
so the arguments will automatically get passed to the function timesTwo if timesTwo is a function object?
Aug 22, 2022 at 11:53am
No. You are effectively passing a pointer to your TimesTwo() function into the for_each() function.

The for_each() function then invokes the given function f – it doesn't really care which function has been passed, as long as that function has the "proper" signature – on every element in the given range.

So, for_each() invokes the function f, via the given function pointer. And, whenever it does so, it passes the required argument to f.

(That's similar to how foo() passes the argument to the given func in my previous example)
Last edited on Aug 22, 2022 at 12:00pm
Aug 22, 2022 at 12:01pm
@kigar64551
so the for_each() will invoke the function timesTwo and as long as the vector type matches the function parameter type and the number of parameter in timesTwo is correct (in this case, only one parameter)
and each time the for_each() will pass the argument to the function timesTwo?

is that correct?
Last edited on Aug 22, 2022 at 12:06pm
Aug 22, 2022 at 12:04pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 

template<typename _InputIterator, typename _Function>
    _Function
    for_each(_InputIterator __first, _InputIterator __last, _Function __f)
    {
      // concept requirements
      __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
      __glibcxx_requires_valid_range(__first, __last);
      for (; __first != __last; ++__first)
	__f(*__first);
      return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant.
    }



so the for_each passes the *__first (deferenced iterator) to the f automatically each time.

This suddenly pop out on my codeblock screen when i tried to modify the number of parameter to 2 in timesTwo function
Last edited on Aug 22, 2022 at 12:05pm
Aug 22, 2022 at 12:06pm
Yes, more or less.

But, note that for_each() is a template function. So the argument type is not fixed! The only requirement is that the given UnaryFunction accepts a single argument of the same type that we get by dereferencing the given InputIt.

In your case, values.cbegin() returns an iterator that dereferences to int values. That is because values is of type array<int, SIZE>. Consequently, the UnaryFunction passed to for_each() must accept a single argument of type int to match the given input iterator.

If the input iterator had a different type, then you'd have to adjust the argument type of your UnaryFunction accordingly.
Last edited on Aug 22, 2022 at 1:10pm
Aug 22, 2022 at 12:08pm
@kigar64551 thank you so much for your help!
Aug 22, 2022 at 12:14pm
can I ask a last question?

is the _Function __f inside the template function being typedef beforehand?


just like the typedef void (*FunctionPtr)(int) you shown just now?



EDIT:
Just realized it is a template function.
meaning _Function __f can accept any type.
Last edited on Aug 22, 2022 at 12:18pm
Aug 22, 2022 at 12:17pm
The template arguments _InputIterator and _Function are replaced with the concrete types to create a concrete instantiation of the template function. In your example, the concrete instantiation of for_each() would look something like this:

1
2
3
4
for_each(array<int,4>::const_iterator __first, array<int,4>::const_iterator __last, void (*__f)(int))
{
    [...]
}


Note: You'd probably get an error in line #11 of the template function, if the given _InputIterator and _Function don't match!
Last edited on Aug 22, 2022 at 12:37pm
Aug 22, 2022 at 12:23pm
very clear explanation. thank you
Topic archived. No new replies allowed.