how does argument get passed to function name

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
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
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
@kigar64551
Do you mind elaborating further?
how is the timesTwo() function a function object?
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
so the arguments will automatically get passed to the function timesTwo if timesTwo is a function object?
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
@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
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
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
@kigar64551 thank you so much for your help!
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
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
very clear explanation. thank you
Topic archived. No new replies allowed.