1

I'm trying to compile the following:

#include <vector> #include <array> template <typename T> void sort(T &container) {} template <typename F, typename T, typename ...Tail> void sort_containers(F sort_func, T &container, Tail &...tail) { sort_func(container); sort_containers(sort_func, tail...); } template <typename F, typename T> void sort_containers(F sort_func, T &container) { sort_func(container); } int main() { std::vector<int> x = {1,2,3}; std::vector<double> y = {1.0, 2.0, 3.0}; std::array<char, 3> z = {{'d' , 'b', 'c'}}; sort_containers(sort, x, y, z); } 

Which leads to the following compiler error with g++4.8:

error: no matching function for call to ‘sort_containers(<unresolved overloaded function type>, std::vector<int>&, std::vector<double>&, std::array<char, 3u>&)’ 

I understand that I need to specify the template parameter for sort when passing it to sort_containers, but I'm not sure how this works in the presence of a variadic template function.

2
  • It works just like it would work with a non-variadic template sort_three_containers. That is, not too well. You need to pass not a function (template) but an object with a member function template that does the sorting, so that its instantiation happens at every recursive call to sort_containers. Commented Jun 2, 2013 at 2:51
  • With a non-variadic template I can do the following: ideone.com/jBg5yT, although I guess this example wouldn't extend to sort_three_containers Commented Jun 2, 2013 at 2:56

1 Answer 1

3

template functions are function factories, not functions. They cannot be passed around directly.

Now, functors can be, and a relatively simple wrapper can turn an overload set of functions into a functor:

struct sort_functor { template<typename...Args> auto operator()(Args&&... args) const -> decltype(sort(std::forward<Args>(args)... ) ) { return sort(std::forward<Args>(args)... ); } }; 

which can be generated via macro, but not by template, because you cannot pass the overload set! You then pass sort_functor() to your other template.

#define MAKE_OVERLOAD_FUNCTOR( NAME ) \ struct CONCAT( NAME, _functor ) { \ template<typename...Args> \ auto operator()(Args&&... args) const -> \ decltype(NAME(std::forward<Args>(args)... ) ) \ { return NAME(std::forward<Args>(args)... ) } \ }; 

There is a proposal to make generating the above functor automagically via further abuse of the [] tokens.

Sign up to request clarification or add additional context in comments.

2 Comments

Pff, "abuse". I'm just leaning on the lambda syntax. :P
I said "further abuse" :) Lambda syntax was the initial abuse @xeo