Reputation: 691
I'm wondering whether it might be possible to create function objects from function templates. The following Functor
struct creates a function object from a function:
#include <iostream>
template <typename F, F* f>
struct Functor {
template <typename... Ar>
auto operator()(Ar&&... rg) -> decltype(f(std::forward<Ar>(rg)...)) {
return f(std::forward<Ar>(rg)...);
}
};
int plus_one(int a) {
return a + 1;
}
int main () {
std::cout << Functor<decltype(plus_one), &plus_one>()(1) << "\n";
return 0;
}
This creates a structure like
struct PlusOne {
int operator()(int a) {
return a + 1;
}
}
Now, I'd like to work with a function template instead of a function:
template <typename T>
T plus_one(T a) {
return a + 1;
}
which I'm hoping to turn into something like
struct PlusOne {
template <class T>
T operator()(T a) {
return a + 1;
}
};
Is this possible? One of the reasons I'm asking this is that I read generic lambda expressions in C++14 are being turned into functors similar to what I'm after:
For example, this generic lambda-expression containing statement:
auto L = [](const auto& x, auto& y){ return x + y; };
might result in the creation of a closure type, and object that behaves similar to the struct below:
struct { template <typename T, typename U> auto operator()(const T& x, U& y) const { return x + y; } } L;
So I was naively hoping some facilities for making possible what I'm after, might exist. I'm restricted to C++11 though.
Upvotes: 6
Views: 392
Reputation: 20579
No, it is not possible. A template name by itself can be used in very limited ways. You have to wrap it in a class before passing it around. In C++14, using a lambda to wrap the call to the function seems to be the simplest possible way. Then you can use it in many ways:
auto wrapper = [](const auto& x){ return plus_one(x); }
std::cout << wrapper(42) << "\n";
std::cout << std::invoke(wrapper, 42) << "\n";
std::cout << std::bind(wrapper, 42)() << "\n";
// etc.
In C++11, we are kinda screwed up. We have to write the wrapper by ourselves:
struct Wrapper {
template <typename T>
auto operator()(const T& x) const
{
return plus_one(x);
}
};
then
Wrapper wrapper;
// same usage
Upvotes: 3