Difference on passing a free function as template argument by value or by reference
Asked Answered
S

1

5

Consider this code (godbolt):

#include <iostream>

template<typename F> void call_by_val(F funct)
   {
    std::cout << "call_by_val(): ";
    funct();
   }

template<typename F> void call_by_ref(F& funct)
   {
    std::cout << "call_by_ref(): ";
    funct();
   }

template<typename F> void call_by_cref(const F& funct)
   {
    std::cout << "call_by_cref(): ";
    funct();
   }


void free_funct()
{
    std::cout << "free_funct()\n";
}


int main()
{
    call_by_val( free_funct );
    call_by_ref( free_funct );
    call_by_cref( free_funct );
}

All of these three calls work as expected. In case of a free function I'm not sure what's happening under the rug, so I'm wandering what's the difference in these three styles, semantically speaking. Is there an objective reason to prefer one over the others?

Springlet answered 2/10, 2024 at 6:53 Comment(9)
consider for example what funct = some_other_function; would do in each caseAlbemarle
For a free function, they're all doing the exact same thing.Cleancut
Non-member ("free") functions will decay to pointers to themselves. In all cases the type of F should be void (*)(). Passing a pointer by reference only makes sense if you want to change the pointer inside the called function.Twittery
@Albemarle I struggle to understand the meaning of modifying or copying the passed function, is the argument of call_by_*(), a pointer?Springlet
@Someprogrammerdude Ah, so I can think of F as a pointer, right? In this case maybe (const F funct) would make sense if meant const pointer to functionSpringlet
Its a reference like all references are gcc.godbolt.org/z/W88Ebxr1x.Albemarle
Fyi, you can pass it as non type template parameter which avoids the function pointer and may yield better optimizations by the compiler (such as inlining)Danialdaniala
@AhmedAEK For that a recent c++ standard is needed, right?Springlet
@Springlet you'll need C++17 for auto NTTP so you don't have to specify the function type, but if you do specify the function type then you need c++98Danialdaniala
S
7

It is impossible to pass functions by-value. When a parameter of a function has a function type it is automatically adjusted to "pointer to [the function type]" instead. Similarly, deduction will decay the argument of function type to a function pointer before deduction if the function parameter is of non-reference type.

So, F in the first call will be void(*)(), not void().

In the reference overloads F will be deduced to void().

const has no meaning for references to functions and so the parameter in both the second and third call will be of type void(&)().

Whether funct is a reference-to-function or pointer-to-function pretty much doesn't matter though, because you can call either as if you named the function directly. There is no difference in meaning except what decltype(funct) would produce.

Schizogony answered 2/10, 2024 at 7:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.