Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing any function as template parameter

I want to pass a function value as a template parameter to a function. Currently the best I managed to do is :

template< typename F, F f > void pass() {     ... } 

...which is used:

pass< decltype(&func), &func >(); 

What I would really like is to have:

pass< &func >(); 

Is there any way to achieve this without macros? Basically to pass both the type and the value at the same time? The compiler obviously has all the information needed for that...

The solution must work with variable parameters and return types. The function value is used at compile time, so it cannot be passed as an argument.

C++11 solutions welcome.


Edit: use case - I'm generating bindings at compile-time, where I need to create a C++ function for each passed function. The use case of this code looks (simplified) more or less like this:

template < typename F, F f >  int function_wrapper( lua_State* L )  {     return dispatcher<typename return_type<F>::type>::call( L, 1, f ); }  void register_native_function( lua_Function f, const char* name ) {     // binding call using pure C function f }  template < typename F, F f > void register_function( const char* name ) {     register_native_function( function_wrapper< F, f >, name ); } 

Please note that I need to create a compile-time function wrapper, so I need the pass function value at compile time. There are binding solutions that allow binding at runtime, but they always require boilerplate code compared to hand-written bindings. I'm aiming to achieve a hand-written performance here.

like image 756
Kornel Kisielewicz Avatar asked Jun 12 '14 13:06

Kornel Kisielewicz


People also ask

Can a template parameter be a function?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.

How do you call a function in a template?

Defining a Function TemplateA function template starts with the keyword template followed by template parameter(s) inside <> which is followed by the function definition. In the above code, T is a template argument that accepts different data types ( int , float , etc.), and typename is a keyword.

Which is correct example of template parameters?

For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.

Can we use non-type parameters as argument templates?

A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.


2 Answers

It's now possible in C++17 with template<auto>:

template<auto Func> struct FuncWrapper final {     template<typename... Args>     auto operator()(Args &&... args) const     {         return Func(std::forward<Args>(args)...);     } };  int add(int a, int b) {     return a + b; }  int main() {     FuncWrapper<add> wrapper;     return wrapper(12, 34); } 

Demo: https://godbolt.org/g/B7W56t

You can use #ifdef __cpp_nontype_template_parameter_auto to detect compiler support for this in your code.

If you are able to use C++20 and you want better error messages, you can also use concepts:

template<typename T> concept CanAddTwoNumbers = std::is_invocable_r_v<int, T, int, int>;  template<auto Func>     requires CanAddTwoNumbers<decltype(Func)> struct AddTwoNumbersWrapper final {     auto operator()(int a, int b) const     -> int     {         return std::invoke(Func, a, b);     } };  int add(int a, int b) {     return a + b; }  int main() {     AddTwoNumbersWrapper<add> wrapper;     return wrapper(12, 34);     AddTwoNumbersWrapper<123> bad; //error: constraint failure } 

Demo: https://gcc.godbolt.org/z/ai3WGH

like image 108
LB-- Avatar answered Sep 21 '22 19:09

LB--


I believe shortening this is currently impossible. A year ago, the C++ committee looked at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3601.html to fix this, and they encouraged the authors to pursue it further after C++14 was released.

like image 24
Jeffrey Yasskin Avatar answered Sep 21 '22 19:09

Jeffrey Yasskin