Consider following case: I have
int bar1();
double bar2();
I want:
foo<bar1>(); // calls bar1, then uses its result.
foo<bar2>(); // calls bar2, then uses its result.
Naive way to write template foo()
is to use additional parameter:
template <typename T, T (*f)()> void foo () {
// call f, do something with result
}
This works, but I need to do ugly syntax:
foo<decltype(bar1()), bar1>(); // calls bar1, then uses its result
I want to write something pretty, like above, just foo<bar1>
.
P.S. Please do not recommend to accept argument at runtime. I need compile time parametrization with function pointer only.
P.S. Sorry forget to mention: I am looking for C++14 solution. C++17 appreciated and I upvoted answer with C++17 solution, but project now builds with C++14 and I can not change it in nearest future.
In order to get
foo<bar1>();
You need template<auto>
from C++17. That would look like
int bar1() { return 1; }
double bar2() { return 2.0; }
template<auto function> void foo() { std::cout << function() << "\n"; }
int main()
{
foo<bar1>();
foo<bar2>();
}
Which outputs
1
2
Live Example
Before C++17 you have to specify the type as there is no auto deduction of the type of a non type template parameters.
So, I'll try to give the best possible answer that I'm aware of in 14. Basically a good approach (IMHO) to this problem is to "lift" the function pointer into a lambda. This allows you to write foo
in the much more idiomatic way of accepting a callable:
template <class F>
void foo(F f);
You still get optimal performance, because the type of the lambda is unique, and so it gets inlined. You can more easily use foo with other things though. So now we have to turn our function pointer into a lambda that is hardcoded to call it. The best we can on that front is drawn from this question: Function to Lambda.
template <class T>
struct makeLambdaHelper;
template <class R, class ... Args>
struct makeLambdaHelper<R(*)(Args...)>
{
template <void(*F)(Args...)>
static auto make() {
return [] (Args ... args) {
return F(std::forward<Args>(args)...);
};
}
};
We use it like this:
auto lam = makeLambdaHelper<decltype(&f)>::make<f>();
To avoid having to mention it twice, we can use a macro:
#define FUNC_TO_LAMBDA(f) makeLambdaHelper<decltype(&f)>::make<f>()
You could then do:
foo(FUNC_TO_LAMBDA(bar1));
Live example: http://coliru.stacked-crooked.com/a/823c6b6432522b8b
I am looking for C++14 solution. C++17 appreciated and I upvoted answer with C++17 solution, but project now builds with C++14 and I can not change it in nearest future.
Unfortunately what you ask works starting from C++17.
If you want use the exactly syntax
foo<bar1>();
I don't thinks it's possible in C++14.
But, if you accept a little different syntax... I know that macros are distilled evil but... if you accept to call foo()
as
FOO(bar1)();
you can define the macro
#define FOO(f) foo<decltype(f()), f>
A full working example
#include <iostream>
#define FOO(f) foo<decltype(f()), f>
int bar1 ()
{ std::cout << "bar1()" << std::endl; return 0; }
double bar2 ()
{ std::cout << "bar2()" << std::endl; return 1.0; }
template <typename T, T (*f)()>
void foo ()
{ f(); }
int main()
{
FOO(bar1)(); // print bar1()
FOO(bar2)(); // print bar2()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With