Reputation: 994
Suppose I have
typedef std::function<
double(
int,
long
)
> FooType;
and I want to declare function prototypes for a series of functions that I can slot into a std::function
of this type. I know I can write
double foo1(int, long);
double foo2(int, long);
etc., but is there a way I can use FooType
somehow when declaring the function prototypes? Something like
FooType::type foo1, foo2;
Perhaps I might have to use (*foo1)
or similar? Naturally in the implementation of the function I'd need to spell it out long hand so I can put in some parameters, but writing it as above would keep my header file cleaner.
Upvotes: 16
Views: 2811
Reputation: 137850
writing it as above would keep my header file cleaner
It would be cleaner (with less metaprogramming) to go the other way around: Start with the foo()
declaration and create FooType
from it.
double foo(int, long);
typedef std::function< decltype(foo) > FooType;
Since there are presumably several such functions, two typedefs might be the optimal factoring:
typedef double FooFn(int, long);
typedef std::function< FooFn > FooType;
FooFn foo1, foo2, foo3;
Of course, in the implementation (.cpp) file the signature needs to be written longhand.
One more thing, note that std::function
is a heavyweight generalization of function pointers. If you'll only ever assign ordinary functions into it, a function pointer might be better, and this would be a drop-in replacement:
typedef FooFn * FooType;
Upvotes: 9
Reputation: 50550
As an alternative solution to the working one presented by @KerrekSB, you can use a function declaration and an alias as it follows if you want to get a pointer type:
#include <functional>
#include <utility>
template<typename F> F * get(std::function<F>);
template<typename F> using FPtr = decltype(get(std::declval<F>()));
double f(int, long) { return {}; }
int main() {
using FooType = std::function<double(int, long)>;
FPtr<FooType> myF = f;
(void)myF;
}
Or a slightly modified version if you want only the actual type:
#include <type_traits>
#include <functional>
#include <utility>
template<typename F> F * get(std::function<F>);
template<typename F> using MyType = typename std::remove_pointer<decltype(get(std::declval<F>()))>::type;
double f(int, long) { return {}; }
int main() {
using FooType = std::function<double(int, long)>;
MyType<FooType> *myF = f;
(void)myF;
}
Upvotes: 0
Reputation: 93304
You can easily do this by creating a template struct
which destructures the type of FooType
, matching T
in std::function< T >
:
template <typename T>
struct destructure;
template <typename T>
struct destructure<std::function<T>>
{
using type = T;
};
template <typename T>
using destructure_t = typename destructure<T>::type;
After that, you can use destructure_t
to declare your function:
destructure_t<FooType> foo;
int main()
{
foo(1, 20l);
}
Then, you can define it with the regular function syntax:
double foo(int i, long l)
{
std::cout << i << " " << l << "\n";
return 0;
}
Your main
will print "1 20".
Upvotes: 4
Reputation: 477150
Sure you can, just as always*, using partial specialization:
template <typename> struct fn_sig;
template <typename T> struct fn_sig<std::function<T>> { using type = T; };
Usage:
fn_sig<FooType>::type f;
double f(int a, long b) { return double(a) / b; }
(You'll obviously need to spell the underlying function type out for the function definition.)
*) Meaning that this is the same answer for any question of the form "can I get the template parameter from a template specializaton".
Upvotes: 19