Универсальные функции, принимающие универсальные функции в качестве аргументов

Я не могу найти хороший способ определить универсальные функции высшего порядка, принимающие универсальные функции в качестве аргументов. Например, возьмем эту попытку для одной из самых простых таких функций:

template<typename F, typename A>
auto apply(F f, const A& a) -> decltype(f(a)){return f(a);}

Конечно, это работает как задумано, когда используется с не шаблонными функциями. Но если у меня есть, например

template<typename A>
A id(const A& a){return a;}

затем

int a = 10;
int b = apply(id, a);

не будет работать, так как id ожидает параметр шаблона. Я мог бы просто написать id<int> чтобы заставить его работать, но это как бы отрицательно сказывается на цели (как я понимаю, это означает, что если бы я хотел написать «фильтр», мне пришлось бы написать отдельное определение для каждой универсальной функции предиката). С помощью std::function или указатели на функции не помогли. Кроме того, я попытался сделать версию шаблона шаблона apply, но я получаю различные ошибки компилятора, когда я пытаюсь использовать его:

template<template<typename> class F, typename A>
auto apply2(F<A> f, const A& a)-> decltype(f(a)){return f(a);}

Лучшее, что я придумал, было следующее:

struct Id{
template<typename A>
static A func(const A& a){return a;}
};

template<typename F, typename A>
auto apply(A a)-> decltype(F::func(a)){return F::func(a);}

Это немного уродливо, но теперь, по крайней мере, я могу на самом деле параметризоваться с помощью функции.

Итак, есть ли лучший способ сделать универсальные функции, принимающие универсальные функции в качестве аргументов?

1

Решение

Этот «функтор» работает с вашей первой версией заявки.

struct id
{
template<typename A>
A operator ()(const A& a) {return a;}
};

потом

int b = apply(id(), a); // with extra parenthesis to construct the struct.
3

Другие решения

В C ++ 11 лучшее, что вы можете сделать, это использовать struct с оператором вызова шаблонной функции:

struct ID {
template <typename T>
void operator()(T arg) const {
...
}
};

Причина, по которой это предпочтительнее функции [указатель], потому что она, скорее всего, будет встроенной. С C ++ 14 вы можете использовать лямбды:

[](auto arg){ ... }

это просто милая версия, чтобы написать struct выше.

1