Как правильно написать функцию test, чтобы ей в качестве аргумента (либо шаблонного параметра - не важно) можно было передать любую из функций f и g, с возможностью их вызова с разным типом аргумента (в примере int, char и long).
http://ideone.com/1aZ8Zu
#include <iostream>
using namespace std;
template <typename T> auto f(T x) -> decltype(x*x)
{
return x * x;
}
template <typename T> T g(T x)
{
return x * x;
}
template <template <class> class F> void test(F f)
{
auto a = f(32);
auto b = f(' ');
auto c = f(2000000000L);
cout << a << ' ' << b << ' ' << c << endl;
}
int main()
{
test(f);
test(g);
return 0;
}
Этот код не компилируется с сообщениями:
prog.cpp:15:47: error: variable or field 'test' declared void
template <template <class> class F> void test(F f)
^
prog.cpp:15:49: error: missing template arguments before 'f'
template <template <class> class F> void test(F f)
^
prog.cpp: In function 'int main()':
prog.cpp:26:8: error: 'test' was not declared in this scope
test(f);
^
Могу порекомендовать в определенном смысле обходной, но в определенном - и прямой путь. В C++14 (а у вас четко указан этот тэг) лямбды тоже могут быть шаблонами.
auto f = [](auto x){ cout << x << endl; return x*x; };
template<typename F> void test(F f)
{
auto a = f(32);
auto b = f(' ');
auto c = f(2000000000ull);
cout << a << ' ' << b << ' ' << c << endl;
}
int main()
{
test(f);
return 0;
}
Вызывается f именно как шаблон (разная для разных аргументов).
Да, это не есть абсолютно строгий и точный ответ на заданный вопрос, но - шаблон в шаблоне вызван :)
Можно использовать лямбду и как уровень косвенности:
template <typename T> T g_(T x)
{
return x * x * x;
}
auto g = [](auto x){ cout << typeid(x).name() << endl; return g_(x); };
template<typename F> void test(F f)
{
auto a = f(32);
auto b = f(' ');
auto c = f(2000000000ull);
cout << a << ' ' << b << ' ' << c << endl;
}
int main()
{
test(g);
return 0;
}
Пример на ideone: http://ideone.com/kfUWtx
Немного теории.
Для того, чтобы можно было вызывать f(42) и f(42L) одновременно - переменная f должна быть типа, у которого определен шаблонный оператор ():
struct F {
template <typename T> void operator () (T value);
};
void test(F f); // работает
Если же переставить шаблон в другое место - то вы не сможете инстанцировать F:
template <typename T> struct F {
void operator () (T value);
};
void test(F f); // ошибка компиляции: F - это шаблон типа, а не тип
Проблема с функциями - в том, что ссылка на шаблонную функцию больше похожа по своим свойствам на вторую форму записи, чем на первую.
Как уже написал @Harry - для неявного создания структуры первого типа можно использовать лябмды:
auto g = [](auto x){ return x*x; };
template<typename F> test(F f); // сюда можно передать переменную g
Это невозможно, в том виде, что Вы хотите. Вы имеете две шаблонных функции test и f, которые встречаются в одном выражении, и в которых тип аргумента должен быть выведен из переданных аргументов. Что может вывести из этой test(f) строчки компилятор? Ничего, т.к. нет никакой уточняющей информации, конкретизирующей, что за версию нужно инстанциировать.
Как развивать веб-проекты в 2026 году: технологии, контент E-E-A-T и факторы доверия
Современные инструменты для криптотрейдинга: как технологии помогают принимать решения
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники