Edwin Rodríguez
Edwin Rodríguez

Reputation: 1257

Parametrize template by function name c++11

Having the following functions

void print(int a) { cout << a << endl; }
void print(std::string a) { cout << a << endl; }

You can do the following template

template <class T> void printT(T a) { print(a); }

Is there some mechanism to parametrize the function name? Something like this:

template <class T, class F> void anyT(T a) { F(a); }

I don't need to be a function template, just some mechanism to achieve the same.

Upvotes: 5

Views: 606

Answers (6)

Marko Popovic
Marko Popovic

Reputation: 4153

You can pass the function using a function pointer:

template <class T> void anyT(T a, void(*F)(T)) { F(a); }

but then you cannot pass a lambda:

auto printStr = [](std::string a) { cout << a << endl; };
anyT(foo, printStr); // This won't compile

An alternative approach would be to use std::function:

template <class T>
void anyT(T a, std::function<void(T)> F) { F(a); }

or a a generic template parameter:

template <class T, class F>
void anyT(T a, F func) { func(t); }

This has a drawback that it cannot resolve overloaded functions, but you can use a helper function:

template<typename F>
std::function<F> make_function(F *funPtr) {
    return std::function<F>(static_cast<F*>(funPtr));
}

and call anyT like this:

string foo = "foo";
anyT(foo, make_function<void(std::string)>(&print));

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275700

This is a useful macro:

#define OVERRIDES_OF(...) [](auto&&...args)->decltype(auto){ return __VA_ARGS__ (decltype(args)(args)...);}

the result is a stateless lambda that forwards to the token provided.

Use:

static const auto printT = OVERRIDES_OF(print);

now printT is an object that wraps all of the overrides of print.

Upvotes: 1

eerorika
eerorika

Reputation: 238401

You can pass the function as a parameter.

template <class T, class F>
void anyT(T a, F f) {
    f(a);
}

The advantage of this compared to passing a function pointer with templated argument type proposed by 101010, is that this works with function pointers as well as functors (instances of any type that implement operator() such as lambdas.

The disadvantage is that getting a function pointer of an overloaded function can be tricky in the context of freely templated parameter. You'd need to use

void (*f)(int) = print;
anyT(a, f);

Or alternatively, wrap it in a lambda as proposed by GuyGreer.

Upvotes: 1

SirGuy
SirGuy

Reputation: 10780

I personally would go with 101010's solution, however you seem to not want to pass the function pointer as a function parameter, but rather only as a template parameter. Here's how you can do that:

    #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");
    }

Unfortunately, it means you have to specify the template parameters for the function every time, which is a drag.

The better solution I think would be to just use a generic template parameter and a lambda:

   template <class T, class F>
   void anyT(T t, F f)
   {
       f(t);
   }

   auto printT = [](auto i){print(i);}
   anyT(0, printT);

The lambda is necessary because passing print directly would be ambiguous, the compiler won't know if you mean print(int) or print(std::string).

Upvotes: 1

Richard Hodges
Richard Hodges

Reputation: 69892

struggling to understand the rationale here. In c++14 we have lambdas with auto arguments. Will this solve it?

#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);
}

Upvotes: 0

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42929

Yes, you could pass the caller as a function pointer that takes as input T like below:

template <class T> void anyT(T a, void(*f)(T)) {
  f(a);
}

Live Demo

Upvotes: 1

Related Questions