Pradhan
Pradhan

Reputation: 16777

Specify a template argument which could bind to a function template

I am trying to write a higher-order function which would wrap around the standard library functions taking input and output iterators. Here's a failed attempt:

#include <algorithm>
#include <iostream>
#include <type_traits>
#include <vector>
using namespace std;

template <template <typename, typename> class Func, typename InpIt, typename UnaryFunction>
decltype(Func<InpIt, UnaryFunction>(declval<InpIt>(), declval<InpIt>(), declval<UnaryFunction>())) Apply(InpIt first, InpIt last, UnaryFunction f)
{
  return Func<InpIt, UnaryFunction>(first, last, f);
}

int main()
{
  vector<int> a(5);
  Apply<for_each>(a.begin(),
                  a.end(),
                  [](int i)
                  {
    cout << i << endl;
  });
  return 0;
}

Clang 3.5 fails with

high.cpp:16:3: error: no matching function for call to 'Apply'
  Apply<for_each>(a.begin(),
  ^~~~~~~~~~~~~~~
high.cpp:8:100: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Func'
decltype(Func<InpIt, UnaryFunction>(declval<InpIt>(), declval<InpIt>(), declval<UnaryFunction>())) Apply(InpIt first, InpIt last, UnaryFunction f)

What is the right way to express this? Also, what I would ideally want is to be able to simply say something like

template <MagicIncantation Func, typename Range, typename ... Args>
MoreMagic Apply(Range&& rng, Args&& ... args)
{
  using std::begin; using std::end;
  Func(begin(rng), end(rng), args...);
}

allowing one to avoid specifying iterators when you want to iterate over the full range.

Upvotes: 4

Views: 404

Answers (2)

Axalo
Axalo

Reputation: 2953

You can use a wrapper class as seen here:

template <template <typename, typename> class Func, typename InpIt, typename UnaryFunction>
UnaryFunction Apply(InpIt first, InpIt last, UnaryFunction f)
{
    return Func<InpIt, UnaryFunction>::f(first, last, f);
}

template<typename T, typename T2>
struct for_each_wrapper
{
    static T2 f(T ta, T tb, T2 t2)
    {
        return std::for_each(ta, tb, t2);
    }
};

int main()
{
    vector<int> a(5);
    Apply<for_each_wrapper>(
        a.begin(),
        a.end(),
        [](int i)
    {
        std::cout << i << endl;
    });
    return 0;
}

Upvotes: 1

Quentin
Quentin

Reputation: 63154

You'll find useful information in this question/answer, but what comes out of it is that you can't pass function templates as template (template) parameters, so passing std::for_each that way is not possible.

Upvotes: 2

Related Questions