Function pointers as template arguments

  • A+

In the following C++ code, the line bar<func_ptr>(); //does not work causes a compilation error:

#include <iostream>  using namespace std;  void foo(){     cout<<"Hello world"; };  template<void(*func)()>  void bar(){     (*func)(); }  int main() {     using fun_ptr_type= void(*)();     constexpr fun_ptr_type func_ptr=&foo;      bar<&foo>();     //works     bar<func_ptr>(); //does not work     return 0; } 

The output of g++ is this:

src/main.cpp: In function ‘int main()’: src/main.cpp:19:16: error: no matching function for call to ‘bar()’   bar<func_ptr>(); //does not work                 ^ src/main.cpp:10:6: note: candidate: template<void (* func)()> void bar()  void bar(){       ^~~ src/main.cpp:10:6: note:   template argument deduction/substitution failed: src/main.cpp:19:16: error: ‘(fun_ptr_type)func_ptr’ is not a valid template argument for ty pe ‘void (*)()’   bar<func_ptr>(); //does not work                 ^ src/main.cpp:19:16: error: it must be the address of a function with external linkage 

I do not understand why it works when I directly pass the address of foo as a template argument but when I pass the constexpr func_ptr, the code does not compile anymore even though it holds exactly that address of foo at compilation time. Can someone explain this to me?

EDIT: My g++ version is

$ g++ --version g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 


From it says:

For pointers to functions, the valid arguments are pointers to functions with linkage (or constant expressions that evaluate to null pointer values). (until C++17).

Since constexpr fun_ptr_type func_ptr=&foo does not evaluate to a nullptr value at compile time, it fails if you run it with -std=c++14 or -std=c++11.

However C++17 imposes no such requirement on function pointer non type template parameters. It says:

The template argument that can be used with a non-type template parameter can be any converted constant expression of the type of the template parameter. (since C++17)

(There are some exceptions to the above but none apply to function pointers).

So the code you provide runs perfectly with the -std=c++17 option.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: