Параметризация шаблона по имени функции 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);
}

Live Demo


я лично пошел бы с решением 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));