Параметризация шаблона по имени функции c++11
имеющий следующие функции
void print(int a) { cout << a << endl; }
void print(std::string a) { cout << a << endl; }
вы можете сделать следующий шаблон
template <class T> void printT(T a) { print(a); }
есть ли какой-то механизм для параметризации имени функции? Что-то вроде этого:--4-->
template <class T, class F> void anyT(T a) { F(a); }
мне не нужно быть шаблоном функции, просто какой-то механизм для достижения того же самого.
6 ответов
Да, вы можете передать вызывающего абонента в качестве указателя функции, который принимает в качестве ввода T
, как показано ниже:
template <class T> void anyT(T a, void(*f)(T)) {
f(a);
}
я лично пошел бы с решением 101010, однако вы, похоже, не хотите передавать указатель функции как параметр функции, а скорее только как параметр шаблона. Вот как вы можете это сделать:
#include <string>
template <class T, void(*func)(T)>
void anyT(T t)
{
func(t);
}
void print(int i){}
void print(std::string s){}
int main()
{
anyT<int, print>(1);
anyT<std::string, print>("hello");
}
к сожалению, это означает, что вы должны каждый раз указывать параметры шаблона для функции, что является перетаскиванием.
лучшее решение, которое я думаю, было бы просто использовать общий параметр шаблона и лямбда:
template <class T, class F>
void anyT(T t, F f)
{
f(t);
}
auto printT = [](auto i){print(i);}
anyT(0, printT);
лямбда необходимо, потому что прохождение print
напрямую было бы неоднозначно, компилятор не будет знать, имеете ли вы в виду print(int)
или print(std::string)
.
вы можете передать функцию в качестве параметра.
template <class T, class F>
void anyT(T a, F f) {
f(a);
}
преимущество этого по сравнению с передачей указателя функции с шаблонным типом аргумента, предложенным 101010, заключается в том, что это работает с указателями функций, а также функторами (экземплярами любого типа, реализующими operator()
такие как лямбда.
недостатком является то, что получение указателя функции перегруженной функции может быть сложным в контексте свободно шаблонного параметра. Вам нужно использовать
void (*f)(int) = print;
anyT(a, f);
или, альтернативно, оберните его в лямбду, как предложил Гайгрер.
Это полезный макрос:
#define OVERRIDES_OF(...) [](auto&&...args)->decltype(auto){ return __VA_ARGS__ (decltype(args)(args)...);}
результатом является лямбда без состояния, которая пересылается на предоставленный токен.
использование:
static const auto printT = OVERRIDES_OF(print);
теперь printT
- это объект, который обертывает все переопределения print
.
пытаются понять причины. В c++14 мы имеем lambdas с автоматическими аргументами. Это решит проблему?
#include <iostream>
int main() {
int a = 1;
std::string str = "string";
auto print = [] (const auto& a) { std::cout << a << std::endl; };
print(a);
print(str);
}
вы можете передать функцию с помощью указателя функции:
template <class T> void anyT(T a, void(*F)(T)) { F(a); }
но тогда вы не сможете пройти лямбда:
auto printStr = [](std::string a) { cout << a << endl; };
anyT(foo, printStr); // This won't compile
альтернативным подходом было бы использование std::function
:
template <class T>
void anyT(T a, std::function<void(T)> F) { F(a); }
или параметр универсального шаблона:
template <class T, class F>
void anyT(T a, F func) { func(t); }
это недостаток, который он не может разрешить перегруженные функции, но вы можете использовать вспомогательную функцию:
template<typename F>
std::function<F> make_function(F *funPtr) {
return std::function<F>(static_cast<F*>(funPtr));
}
и звонок anyT
такой:
string foo = "foo";
anyT(foo, make_function<void(std::string)>(&print));