Использование типа функции в std:: function для объявления нескольких функций этого типа
Предположим, что
typedef std::function<
double(
int,
long
)
> FooType;
и я хочу объявить прототипы функций для ряда функций, которые я могу сложить в std::function
этого типа. Я знаю, что могу написать
double foo1(int, long);
double foo2(int, long);
и т.д., но есть ли способ, каким образом я могу использовать FooType
при объявлении прототипов функций? Что-то вроде
FooType::type foo1, foo2;
Возможно, мне, возможно, придется использовать (*foo1)
или подобное? Естественно, в реализации функции мне нужно было бы написать ее длинную руку, чтобы я мог вставить некоторые параметры, но запись ее, как указано выше, сохранит мой файл заголовка чистым.
Ответы
Ответ 1
Конечно, вы можете, как всегда *, использовать частичную специализацию:
template <typename> struct fn_sig;
template <typename T> struct fn_sig<std::function<T>> { using type = T; };
Использование:
fn_sig<FooType>::type f;
double f(int a, long b) { return double(a) / b; }
(Очевидно, для определения функции вам, вероятно, потребуется указать базовый тип функции.)
*) Значение того, что это тот же ответ на любой вопрос о форме "могу ли я получить параметр шаблона из специализированного шаблона".
Ответ 2
запись его, как указано выше, сохранит мой файл заголовка
Было бы проще (с меньшим метапрограммированием) пойти наоборот: Начните с объявления foo()
и создайте FooType
из него.
double foo(int, long);
typedef std::function< decltype(foo) > FooType;
Так как существует предположительно несколько таких функций, оптимальным факторингом может быть два typedefs:
typedef double FooFn(int, long);
typedef std::function< FooFn > FooType;
FooFn foo1, foo2, foo3;
Конечно, в файле реализации (.cpp) подпись должна быть написана долго.
Еще одна вещь, обратите внимание, что std::function
представляет собой тяжелое обобщение указателей на функции. Если вы только присвоите ему обычные функции, указатель функции может быть лучше, и это будет замена:
typedef FooFn * FooType;
Ответ 3
Вы можете легко сделать это, создав шаблон struct
, который разрушает тип FooType
, сопоставляя T
в 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;
После этого вы можете использовать destructure_t
для объявления своей функции:
destructure_t<FooType> foo;
int main()
{
foo(1, 20l);
}
Затем вы можете определить его с помощью регулярного синтаксиса функции:
double foo(int i, long l)
{
std::cout << i << " " << l << "\n";
return 0;
}
Ваш main
будет печатать "1 20".
пример wandbox
Ответ 4
В качестве альтернативного решения для рабочего, представленного @KerrekSB, вы можете использовать объявление функции и псевдоним, как следует, если вы хотите получить тип указателя
#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;
}
Или немного модифицированная версия, если вы хотите только фактический тип:
#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;
}