How to Pass a Template Function in a Template Argument List

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

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 templated class without it's argument list as a template argument?

You can make container a template template parameter, and you declare createContainer1 twice in main. This compiles:

#include <iostream>

template <typename T>
class Container1 {};

template <typename T>
class Container2 {};

template <typename type, template<class> class container>
class CreateContainer
{
container<type> createContainer()
{
return container<type>();
}

container<const type> createConstContainer()
{
return container<const type>();
}
};

int main()
{
CreateContainer<int,Container1> createContainer1;
CreateContainer<int,Container2> createContainer2;
}

Note that this assumes that the container template parameter has a single type parameter. It wont work for eg for a template <typename T,size_t foo> struct container3 {};, but it could be made to work, if you need that.

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

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

Pass a templated function as argument to another function

Function parameters are variables. Not variable templates; just regular old variables. And a non-template variable cannot be given template parameters.

You cannot pass a function template anywhere. You can only pass a particular instantiation of a function template. The closest you can get to what you want is to pass a type that has a templated operator() overload, but unless you can provide the template parameters through deduction, the only way to invoke it is via fn.operator()<TemplateArguments>(params). So you may as well have given it a meaningful name.

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.

How to pass any number of arguments to C++ template function?

It may be that you are not using the parameter pack in the correct way.

Correct usage:

template <typename T1, typename T2, auto Method, class ...Args>
T1 * wrapObject(Args &&... args)
{
T2 * obj = (*_asposeObj.*Method)(args...);
...
}

With perfect forwarding:

template <typename T1, typename T2, auto Method, class ...Args>
T1 * wrapObject(Args &&... args)
{
T2 * obj = (*_asposeObj.*Method)(std::forward<Args>(args)...);
...
}

Learn more: What are the main purposes of using std::forward and which problems it solves?

Is there a way to pass templated function signature as a template template parameter

In the example below one has a template template parameter that accepts the preferred signature for the function.

Because of the specialization and the lack of a body for the template class, only types for callables are accepted.

It is a generalization of what the OP actually asked:

#include<cassert>

template<typename F>
struct S;

template<typename R, typename... Args>
struct S<R(Args...)> {
using type = R(*)(Args...);
};

template<template<typename> class F>
struct T {
typename F<void(int)>::type ft;
typename F<double(double, double)>::type gt;
};

void f(int) { }
double g(double x, double y) { return x+y; }

int main() {
T<S> t;
t.ft = f;
t.gt = g;
t.ft(42);
auto v = t.gt(1., 1.);
assert(v == 2.);
}


Related Topics



Leave a reply



Submit