1

I want to write a simple function to simplify std::transform for a transformation on a single vector.

What I've got so far:

template<typename T>
void transform(std::vector<T> &vec, const std::function<T(const T &)> &fun) {
  std::transform(std::begin(vec), std::end(vec), std::begin(vec), fun);
}

Now when I want to use this function I can write, for example:

transform<int>(vec, my_function);

But I would prefer if I could just use

transform(vec, my_function);

Is there a way to adjust my code to automatically infer the type?

error:

no matching function for call to 'transform' and note: candidate template ignored:
could not match 'function<type-parameter-0-0 (const type-parameter-0-0 &)>' 
against '(lambda at [...]
Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Seims
  • 154
  • 2
  • 7
  • @songyuanyao I get `error: no matching function for call to 'transform'` and `note: candidate template ignored: could not match 'function' against '(lambda at [...]` – Seims Oct 20 '18 at 11:28

3 Answers3

3

It seems you're using lambda as the argument; lambda could be converted to std::function, but implicit conversion won't be considered in template argument deduction, that's why it fails.

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

You can use static_cast explicitly to convert the lambda to std::function when passing it, or stop using std::function. e.g.

template<typename T, typename F>
void transform(std::vector<T> &vec, F fun) {
  std::transform(std::begin(vec), std::end(vec), std::begin(vec), fun);
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
1

Another way to use std::function argument, if for some reason you need it, is to disable type deduction for T in it by moving T into a non-deduced context:

template<typename T>
struct Identity { using Type = T; };

template<typename T>
using Id = typename Identity<T>::Type;

template<typename T>
void transform(std::vector<T>&, const std::function<Id<T>(const Id<T>&)>&);
Evg
  • 25,259
  • 5
  • 41
  • 83
0

You are over-constraining both arguments, and try to use template-deduction and implicit-conversion at the same time for the second, which cannot work. Dispensing with that, and optionally using SFINAE, makes things work properly, more efficient and flexible:

using std::begin;
using std::end;

template <class Range, class F>
auto transform(Range&& range, F f)
noexcept(noexcept(std::transform(begin(range), end(range), begin(range), f)))
-> decltype(std::transform(begin(range), end(range), begin(range), f))
{ return std::transform(begin(range), end(range), begin(range), f); }

Yes, the function-object is copied. If you don't want that, simply pass a std::reference_wrapper using std::ref, just like for the standard-library algorithms.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118