Function Passed as Template Argument

Function passed as template argument

Yes, it is valid.

As for making it work with functors as well, the usual solution is something like this instead:

template <typename F>
void doOperation(F f)
{
int temp=0;
f(temp);
std::cout << "Result is " << temp << std::endl;
}

which can now be called as either:

doOperation(add2);
doOperation(add3());

See it live

The problem with this is that if it makes it tricky for the compiler to inline the call to add2, since all the compiler knows is that a function pointer type void (*)(int &) is being passed to doOperation. (But add3, being a functor, can be inlined easily. Here, the compiler knows that an object of type add3 is passed to the function, which means that the function to call is add3::operator(), and not just some unknown function pointer.)

How to pass a template function as an argument in C++?

You need to specify the template argument for display explicitly:

iter(arr, 3, display<int>);

Or make iter taking function pointer:

template <class T_arr>
void iter(T_arr *arr, int len, void (*func)(T_arr))
{
for(int i = 0; i < len; i++)
{
func(arr[i]);
}
}

then you can

iter(arr, 3, display); // template argument gets deduced as int

Passing any function as template parameter

I believe shortening this is currently impossible. A year ago, the C++ committee looked at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3601.html to fix this, and they encouraged the authors to pursue it further after C++14 was released.

How to pass a function template as a template argument?

You will have the same issue with other io manipulators that typically are functions that take the stream as parameter, when they are templates. Though you can wrap them in a non-template callable:

#include <iostream>

template<typename... Args>
void print(Args const&... args)
{
(std::cout << ... << args);
}

int main()
{
std::cout << 1 << 2 << 3 << std::endl; // ok
print(1, 2, 3); // ok
print(1, 2, 3, [](std::ostream& o) -> std::ostream&{
o << std::endl;
return o;
}); // no error!
}

Output:

123
123123

The syntax is rather heavy so you might want to use a helper type, though I'll leave it to you to write that (just joking, I don't think it is trivial, but I might give it a try later ;). After pondering about it for a while, I am almost certain that there are only the two alternatives: Instantiate the function (see other answer), or wrap the call inside a lambda, unless you want to write a wrapper for each single io manipulator of course.

Is there any workaround for passing a function template as a template parameter?

You can't pass a templated function as a template argument unfortunately unless you specify the template arguments explicitly, e.g.:

template<auto T>
auto func(auto&&... args) {
return T(std::forward<decltype(args)>(args)...);
}

struct Foo { Foo(int i) {} };

int main() {
auto unique_foo = func<std::make_unique<Foo, int>>(1);
}

You can however pass around templated function objects without problems, so the following would work:

template<class T>
struct unique {
auto operator()(auto&&... args) {
return std::make_unique<T>(std::forward<decltype(args)>(args)...);
}
};

template<class T>
struct shared {
auto operator()(auto&&... args) {
return std::make_shared<T>(std::forward<decltype(args)>(args)...);
}
};

template<template<class> class F, class T, class... Args>
requires std::is_invocable_v<F<T>, Args...>
auto func(Args&&... args) {
return F<T>{}(std::forward<Args>(args)...);
}

struct Foo { Foo(int i) {} };

int main(){
auto foo_unique = func<unique, Foo>(1);
auto foo_shared = func<shared, Foo>(2);
}

godbolt example

If you also need to deduce the template parameters of your class by the parameters passed to std::make_unique (like in your linked example), you can add an overload for func that deals with templated types:

template<template<class...> class T, class... Args>
using deduced_type = decltype(T{std::declval<Args>()...});

template<template<class> class F, template<class...> class T, class... Args>
requires std::is_invocable_v<F<deduced_type<T,Args...>>, Args...>
auto func(Args&&... args) {
return F<deduced_type<T, Args...>>{}(std::forward<Args>(args)...);
}

godbolt example

that deduces the template parameters to your type T based on the passed in parameters.

template<class A, class B>
struct Foo { Foo(A,B) {} };

struct Bar { Bar(int i) {} };


int main(){
// automatically deduces the types for A, B in Foo based on arguments
auto foo_unique = func<unique, Foo>(1, 2);

// the normal overload of func handles non-templated classes:
auto bar_unique = func<unique, Bar>(1);
}

Pass a function as an explicit template parameter

The problem here is, multiply is not a type; it is a value but the function template bar expects the template argument to be a type. Hence the error.

If you define the function template as:

template <int (*F)(int,int)> //now it'll accept multiply (i.e value)
void bar(int x, int y)
{
cout << F(x, y) << endl;
}

then it will work. See online demo : http://ideone.com/qJrAe

You can simplify the syntax using typedef as:

typedef int (*Fun)(int,int);

template <Fun F> //now it'll accept multiply (i.e value)
void bar(int x, int y)
{
cout << F(x, y) << endl;
}

Function pointers passed as template arguments

Is this doing what I think it's doing, ie., statically bound call of a function pointer?

Yes, this is doing exactly what you think it's doing. It binds the argument as part of the type itself so that it's not needed to be passed as a runtime argument

Does the template parameter need to be auto for this to work?

No -- auto just makes it more flexible so that it may accept an instance of any invokable object -- whether it's a function pointer, a general lambda, or even a functor object.

For function pointers specifically, this could also have been written:

template <typename R, typename...Args>
class signal<R(Args...)>
{
...
template <R(*Fn)(Args...)>
auto connect() -> void;
...
};

But note, however, that in doing this it forces the exact signature -- which is not quite as expressive. For example, you can't do:

float add(float, float);

auto sig = signal<double(double,double)>{};

sig.connect<&add>(); // error: float(*)(float, float) cannot be converted to double(*)(double, double) for template param

With auto, it allows you to deduce the argument type -- and can allow a template such as this to support implicit conversions -- which can actually be quite powerful if used correctly. This is kind of like how std::function can bind a function with similar but not identical arguments and have it still work -- except this is all done statically rather than dynamically.


In case you're curious why this pattern is used over a runtime argument, it's because it enables a really simple form of type-erasure when building a callback system. Keeping the function statically allows the compiler to inline the code much better than std::function can, and it also has a smaller memory footprint.

By using function templates, the signature of the instantiated function template never changes -- which allows a homogeneous way of storing this for later:

template <typename R, typenmae...Args>
class delegate<R(Args...)> {
...
// The function that will expand into the same pointer-type each time
template <auto Fn>
static auto invoke_stub(Args...) -> R;

...
// The stub to store
R(*m_stub)(Args...);
...
};

For a delegate<int(int)>, it doesn't matter if the invoke_stub is expanded with a function pointer of type short(*)(short), int(*)((short), etc -- the decltype(invoke_stub<...>) will still always yield R(*)(Args...) -- which makes it really easy to store this internally so that it can be called back later.

(Note: this description is a little simplified -- usually the stub contains slightly more info to support member functions)

For a more in-depth breakdown of how this could be done, you can check out some tutorials I authored a few months ago that is coincidentally on exactly this topic: Creating a fast and efficient delegate. Part 2 discusses auto parameters, and Part 3 compares execution times with raw function pointers.

Why can't template functions be passed as a template template parameter?

I don't know for sure the answer to the question of why C++ does not provide function template template parameters, but I imagine it has something to do with:

  • Any nontrivial change to templates will require complicated analysis to determine what changes need to be made to the standard text
  • This feature would be rarely used; after all, class template template parameters are mostly used in partial specializations, i.e., to dispatch on types that are themselves template specializations, and it's rare to want to do that with functions
  • It wouldn't make sense to support function template template parameters without also supporting a type of template parameter that would accept any non-template function (we can do this in C++17 with auto but this is obviously way too late for C++98 to have function template template parameters)
  • You can work around the lack of function template template parameters using class templates anyway (sort of like what we do with partial specializations).
  • Function overloading complicates things. In the presence of overloading, there's no way to unambiguously name a particular function template. Should one be provided? Or, do we take the point of view that an overload set is meant to be passed as a whole to a function template template parameter? What if overload resolution then selects a non-template overload? How do we even answer these design questions without having a compelling use case?

If you believe that you know how to address all these concerns, and in particular can provide a compelling argument for why we need this feature in the language despite the fact that it would be complicated and we can work around its absence using class template template parameters, feel free to write up a proposal for the standard.

Sleek way to use template function as function argument?

As it is not clear why you need APPLY_FUNCTION and SOMETHING as separate template arguments, or why you need them as template arguments at all, I'll state the obvious solution, which maybe isn't applicable to your real case, but to the code in the question it is.

#include <iostream>

template<int SOMETHING>
inline void apply_x(int a, int b) {
std::cout << a << " " << b;
}

template<int SOMETHING>
inline void apply_y(int a, int b) {
std::cout << a << " " << b;
}

template<typename F>
void apply_10_times(int a, int b,F f) {
for (int i = 0; i < 10; i++) {
f(a, b);
}
}

int main() {
int a = 4;
int b = 7;
apply_10_times(a, b,apply_x<17>);
apply_10_times(a, b,apply_y<24>);
}

If you want to keep the function to be called as template argument you can use a function pointer as non-type template argument:

template<void(*F)(int,int)>
void apply_10_times(int a, int b) {
for (int i = 0; i < 10; i++) {
F(a, b);
}
}

int main() {
int a = 4;
int b = 7;
apply_10_times<apply_x<17>>(a, b);
apply_10_times<apply_y<24>>(a, b);
}

In any case I see no reason to have APPLY_FUNCTION and SOMETHING as separate template arguments. The only gain is more complex syntax which is exactly what you want to avoid. If you do need to infer SOMETHING from an instantiation of either apply_x or apply_y, this is also doable without passing the template and its argument separately, though again you'd need to use class templates rather than function templates.


PS:

Ah, now I understand what you mean. Yes, apply_10_times() also uses SOMETHING directly. Sorry, I simplified the code in the question too much.

As mentioned above. This does still not imply that you need to pass them separately. You can deduce SOMETHING from a apply_x<SOMETHING> via partial template specialization. This however requires to use class templates not function templates:

#include <iostream>

template <int SOMETHING>
struct foo {};

template <int X>
struct bar {};

template <typename T>
struct SOMETHING;

template <template <int> class T,int V>
struct SOMETHING<T<V>> { static constexpr int value = V; };

int main() {
std::cout << SOMETHING< foo<42>>::value;
std::cout << SOMETHING< bar<42>>::value;
}

C++ , Member function passed as template argument

  1. Is there any more comfortable way how to pass a member function while keeping the call it as static?

With C++11 and lambda, you may do

template <typename T>
void Algo1<T>::anal(T &c) {
Algo2<T>::process([=](T a1, T& a2) { return this->eval2(a1, a2); }, this->b, c);
}

Before, you have to create your functor manually, something like:

template<typename T>
class MyFunctor
{
public:
explicit(Algo1<T>* algo1) : algo1(algo1) {}

void operator () (T a1, T& a2) const
{
algo1->eval2(a1, a2);
}
private:
Algo1<T>* algo1;
};

And then:

template <typename T>
void Algo1<T>::anal(T &c) {
Algo2<T>::process(MyFunctor<T>(this), this->b, c);
}


Related Topics



Leave a reply



Submit