Question

I define a set of function templates:

template < typename type >
void foo ( type object )
{
    //  foo the object
}

template < typename type >
void bar ( type object )
{
    //  bar the object
}

template < typename type >
void baz ( type object )
{
    //  baz the object
}

Now I want to define a function template which takes a pointer to any of the functions from the above.

    template < /* ??? */ , typename T , typename... TT >
    void for_each ( T parameter , TT... other parameters )
    {
       // process the first parameter using the function pointer defined by the first template parameter
       // recursice call to for_each
    }

What is the correct way to declare the first template parameter?

P.S. I do know that there is a workaround to wrap the first three functions each in a class and make them static. I just want to know if there is a straight way to solve the problem.

Was it helpful?

Solution 2

struct foo_overload_set_t {
  template<typename... Ts>
  auto operator()(Ts&&... ts) const
  -> decltype( foo(std::forward<Ts>(ts)...) ) {
      return ( foo(std::forward<Ts>(ts)...) );
  }
};
static const foo_overload_set_t foo_overload_set;

now foo_overload_set is a single object which can be treated like a function, and when invoked does overload resolution on the function foo based off the passed in parameters.

Ie, foo( a, b, c, d, e ) runs the same code and gives the exact same result as foo_overload_set( a, b, c, d, e ) for any set of arguments.

But foo_overload_set is an object, while foo is an indeterminate set of functions created on the fly based off parameters used to call it.

We can pass said object to your for_each:

template<typename OverloadSet>
void for_each( OverloadSet ) {} // do nothing

template < typename OverloadSet , typename T , typename... TT >
void for_each ( OverloadSet overload, T&& parameter , TT&&... other_parameters )
{
   overload( std::forward<T>(parameter) );
   for_each( overload, std::forward<TT>(other_parameters)... );
}

invoked like:

for_each( foo_overload_set, a, b, c, d, e );

which proceeds to call foo on a, then on b, then on c, etc.

OTHER TIPS

Template template parameters can only be class templates, not function templates, so you'd have to wrap the function template in a class template:

template<typename T>
struct foo_wrap {
    static constexpr void (*fn)(T) = &foo<T>;
};

In C++1y you might consider streamlining this with a generic lambda, although that would be a function parameter, not a template parameter:

for_each(..., [](auto t) { foo(t); }, ...);

template template arguments have to be classes.

#include <iostream>

template <typename... T> void ignore( T... ) {}

template < template < typename T > class f_, typename... args_>
void fun( args_&&... args) {
    int dummy[] { ( f_<args_>{}( std::forward<args_>(args) ), 0)...};
    ignore(dummy);
}

template < typename T > 
struct bar {
    void operator()( T v )  const {
        std::cout << v << " ";
    }
};

int main() {
  int a{1}, b{2}, c{3};
  float d{4.5};
  fun<bar>(a, b, c, d );
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top