Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto deduce type of function in template

I have simple map implementation and simple id (identity):

template <typename T>
T map(const T& x, std::function<decltype(x[0])(decltype(x[0]))> f) {
    T res(x.size());
    auto res_iter = begin(res);
    for (auto i(begin(x)); i < end(x); ++i) {
        *res_iter++ = f(*i);
    }
    return res;
}

template <typename T>
T id(T& x) {return x;}

and when I call is as

vector<int> a = {1,2,3,4,5,6,7,8,9};
map(a, id<const int>);

it works, but I want call it without type specification, like this:

map(a, id);

and when I do it, I get error:

error: cannot resolve overloaded function 'id' based on conversion to type 'std::function<const int&(const int&)>'
 map(a, id);
          ^

How can I resolve it and why can't compiler deduce type of id from its context in map when error contains right bounded type?

like image 225
Shadasviar Avatar asked Mar 24 '26 09:03

Shadasviar


1 Answers

If you are in a C++14 compliant environment, there is a very clean way to do this. Instead of using std::function and a templated class, use an unconstrained forwarding reference and a generic lambda as follows:

#include <vector>

template <typename T,typename F>
T map(const T& x, F &&f) {
  T res(x.size());
  auto res_iter = begin(res);
  for (auto i(begin(x)); i < end(x); ++i) {
    *res_iter++ = f(*i);
  }
  return res;
}

auto id = [](auto x) { return x;};

int main()
{
  std::vector<int> v = {1, 2, 3, 4};
  auto v2 = map(v, id);
}

In C++11, you would have to replace the generic lambda with a functor whose operator() is a templated method, as follows:

struct {
  template<typename T>
  T operator()(T x) const
  {
    return x;
  }
} id;

In C++98 syntax you will not be able to use the forwarding reference, so you will have to consider copying and functor mutability issues.

like image 90
Ansel Sermersheim Avatar answered Mar 25 '26 21:03

Ansel Sermersheim