2

In the question Function passed as template argument, it was asked and explained that there are two traditional ways of passing a function as a template argument in C++, they're:

  1. Declaring the function as a "functor" (e.g. an object with an overridden () operator). But it requires modifying the target function first.
  2. Using function pointer as the parameter, and taking the address of the function with the & operator to use the template. But this can possibly inhibit compiler optimization, especially inlining, since the compiler may be unable to figure out the target of the naked pointer.

I have read and conceptually understood both methods. However, in a comment by user pfalcon under the answer, it was claimed that:

Fast forward to few years later, situation with using functions as template arguments much improved in C++11. You no longer bound to use Javaisms like functor classes, and can use for example static inline functions as template arguments directly. Still far cry comparing to Lisp macros of 1970s, but C++11 definitely has good progress over the years.

But no explanation or example is given. What are the supposedly "much improved" ways of doing that in C++11 that pfalcon was referring to? I tried to search "function as template argument C++11" but I didn't see any usable result.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
比尔盖子
  • 2,693
  • 5
  • 37
  • 53
  • 1
    See : https://en.cppreference.com/w/cpp/17 and lookup the templates section and lambdas – Pepijn Kramer Jun 13 '23 at 09:04
  • related https://stackoverflow.com/questions/10876930/should-one-never-use-static-inline-function – 463035818_is_not_an_ai Jun 13 '23 at 09:13
  • It actually sound like my comment from Quora or someone\somebot repeating me out of context. It was related lambdas and their further evolution, generic lambdas – Swift - Friday Pie Jun 13 '23 at 09:37
  • 1
    C++11 didn't so much change mechanisms to pass functions - it introduced new/extended ways to create function objects, such as lambdas (a shorthand to define a function object [aka functor] which is [if no data is captured] convertible to a function pointer), parameter packs (support templates with variable arguments). It also extended the standard library with means to invoke functions (e.g. `std::invoke`) and with wrappers for functions and their arguments (e.g. `std::function`, reference wrappers) which deprecating some older binders and adaptors (which were later removed from C++17). – Peter Jun 13 '23 at 11:20

1 Answers1

3

Up until C++11, it was not possible to use functions internal linkage as arguments for NTTPs (non-type template parameters). For example, compiling the following code with -std=c++98 fails:

template <void(*fun)()>
void call() {
    fun();
}

// removing static is necessary in C++98
static void callback() {}

void foo() {
    call<callback>();
}
<source>:9:19: error: 'callback' is not a valid template argument
      |                for type 'void > (*)()' because 'void callback()'
      |                does not have external linkage
      |
    9 |     call<callback>();
      |     ~~~~~~~~~~~~~~^~

This is due to this section:

14.3.2 Template non-type arguments

1 A template-argument for a non-type, non-template template-parameter shall be one of:

  • [...]
  • the name of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as id-expression; or
  • [...]

- [temp.arg.nontype] §1

This restriction was lifted in C++11, allowing you to use functions with internal linkage for NTTPs as well. Before, callback would require external linkage, which is problematic if this code all written in a source file, because other source files containing their own callback would conflict with our callback.

In C++11, you are still not allowed to use lambda expressions as template arguments, and creating your own callable types is more verbose, so the above code is as concise as it gets.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
  • Would you elaborate "which is problematic if this code all written in a source file"? – Cloud Cho Jun 23 '23 at 05:59
  • 1
    @CloudCho it means that if there is another source file which also defines a `callback` with external linkage, you can have conflicting definitions and get linker errors. If this code is all written in a source file, you also have no way of controlling what other source files define, contrary to using headers to exchange some information between them. – Jan Schultke Jun 23 '23 at 06:09