Template Function as a Template Argument

Template function as a template argument

In order to solve this problem with templates, you have to use a template template parameter.
Unfortunately, you cannot pass template template function as a type, because it has to be instantiated first. But there is a workaround with dummy structures. Here is an example:

template <typename T>
struct a {

static void foo (T = T ())
{
}

};

template <typename T>
struct b {

static void foo (T = T ())
{
}

};

struct SomeObj {};
struct SomeOtherObj {};

template <template <typename P> class T>
void function ()
{
T<SomeObj>::foo ();
T<SomeOtherObj>::foo ();
}

int main ()
{
function<a>();
function<b>();
}

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

How to pass a template function in a template argument list

I suspect the answer is "you cannot do this".

Yes, that is the case, you cannot pass a function template as a template argument. From 14.3.3:

A template-argument for a template template-parameter shall be the
name of a class template or an alias template, expressed as
id-expression.

The template function needs to be instantiated before you pass it to the other template. One possible solution is to pass a class type that holds a static produce_5_function like so:

template<typename T>
struct Workaround {
static T produce_5_functor() { return T(5); }
};
template<template<typename>class F>
struct client_template {
int operator()() const { return F<int>::produce_5_functor(); }
};
int five = client_template<Workaround>()();

Using alias templates, I could get a little closer:

template <typename T>
T produce_5_functor() { return T(5); }

template <typename R>
using prod_func = R();

template<template<typename>class F>
struct client_template {
int operator()(F<int> f) const { return f(); }
};

int five = client_template<prod_func>()(produce_5_functor);

A template function as a template argument

You can't have a template template parameter that accepts function templates, only class templates. Luckily we can make a class that looks rather like a function.

#include <vector>

template <class T>
struct CopyVector { void operator()() { std::vector<T> v; /*...*/} };

template <class T>
struct CopyVectorAsync{ void operator()() { std::vector<T> v; /*...*/} };

template <template <class> class copy>
void Test()
{
copy<char>{}();
copy<short>{}();
copy<int>{}();
}

int main()
{
Test<CopyVector>();
Test<CopyVectorAsync>();
}

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.

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.)

Template function where template argument type depends on function arguments

I would like to ensure that h and l are the same type (say T),

It's simple: you can impose they are of the same template type T, so if you call the function with values of different types, you get a compilation error because there is ambiguity deducing T.

So

template <typename U, typename T>
void bound_check (U v, T l, T h)
{ /* ... */ }

I would like to ensure that h and l are the same type (say T), and T to be at least timplicitly convertible to decltype(v).

You can check it with a static_assert() (see Nikos C. answer) or you can also SFINAE activate/deactivate the function (by example, in a C++11 way) as follows

template <typename U, typename T>
typename std::enable_if<std::is_convertible<T, U>::value>::type bound_check (U & v, T l, T h)
{ /* do something with v, l and h */ }

I made an (arguably more dangerous) assumption that all possible type Ts are signed

Using SFINAE, you can add the corresponding test

template <typename U, typename T>
typename std::enable_if<std::is_convertible<T, U>::value
&& std::is_signed<T>::value>::type bound_check (U & v, T l, T h)
{ /* do something with v, l and h */ }

Maybe you can also check that T is an integral type (std::is_integral): std::is_signed is true also for floating point types.

if there is some trick to do template bound_check(T& v) where type are deduced from arguments before explicit template arguments are parsed, as the title says.

No, as far I know.

Anyway, if possible, this way you loose the "I would like to ensure that h and l are the same type" check.

If wonder if there's a way that I can call the function as in bound_check<l, h>(v)

Starting from C++17, you can use auto for non-type template parameter.

So, before C++17 I suppose the answer is "no".

Starting from C++17, you could write something as

template <auto l, auto h, typename U>
std::enable_if_t<std::is_same_v<decltype(l), decltype(h)>
&& std::is_convertible_v<decltype(l), U>
&& std::is_integral_v<decltype(l)>
&& std::is_signed_v<decltype(l)>> bound_check (U & v)
{ /* do something with v, l and h */ }

template template function parameter

f is supposed to be a class - you have a function.

See below:

// Class acts like a function - also known as functor.
template<typename T, int a, int b>
class f
{
int operator()(T v)
{
return v*a-b; // just do something for example
}
};

template<typename T, int a, int b, template<typename,int,int> class func>
class C
{
int f()
{
return func<T,a,b>(3);
}
};

int main()
{
C<float,3,2, f> c;
}

... And the adapted version if you need to port legacy code (Adapts the function to a class template):

#include <iostream>

template<typename T, int a, int b>
int f(T v)
{
std::cout << "Called" << std::endl;
return v*a-b; // just do something for example
}

template<typename T, int a, int b, template<typename,int,int> class func>
struct C
{
int f()
{
return func<T,a,b>(3);
}
};

template <class T, int a, int b>
struct FuncAdapt
{
T x_;
template <class U>
FuncAdapt( U x )
: x_( x )
{}
operator int() const
{
return f<T,a,b>( x_ );
}
};

int main()
{
C<float,3,2, FuncAdapt > c;
c.f();
}

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

Making a template function mirror its template argument's signature

You can create traits to extract returs type and parameters. issue would be to handle arity only from function declaration.

If you can wrap in a class/functor, it would be possible:

template <auto func> struct wrapper_t;

template <typename Ret, typename ... Ts, Ret (*func)(Ts...)>
struct wrapper_t<func>
{
Ret operator() (Ts... args) const { return func(std::forward<Ts>(args)...); }
};

// handle ellipsis functions ala printf
template <typename Ret, typename ... Ts, Ret (*func)(Ts..., ...)>
struct wrapper_t<func>
{
template <typename ...EllipsisArgs>
Ret operator() (Ts... args, EllipsisArgs&&... ellipisisArgs) const {
return func(std::forward<Ts>(args)...,
std::forward<EllipsisArgs>(ellipisisArgs)...);
}
};

template <auto func>
constexpr wrapper_t<func> wrapper{};

Demo



Related Topics



Leave a reply



Submit