sebastian
sebastian

Reputation: 2506

std::map transformer template

The following template for a std::map transformation function doesn't work. If I use transform_map(), the compiler cannot deduce the types to find the template. How can it be done?

template <class Key, class FromValue, class ToValue, class Transformer>
std::map<Key, ToValue> transform_map(const std::map<Key, FromValue>& _map,
    Transformer _tr) {
  std::map<Key, ToValue> res;
  std::for_each(_map.cbegin(), _map.cend(), 
      [&res, &_tr](const std::pair<const Key, FromValue>& kv) {
        res[kv.first] = _tr(kv.second);
      });
  return res;
}

Upvotes: 3

Views: 96

Answers (1)

super
super

Reputation: 12928

The deduction of a function template is done on the parameters you pass in. Since ToValue is not related to any of the passed in parameters it can not be deduced.

You can solve this by telling the compiler to default to the value that would be returned if you call Transformer with a FromValue.

#include <iostream>
#include <map>
#include <algorithm>

template <class Key, class FromValue, class Transformer, class ToValue = decltype(std::declval<Transformer>()(std::declval<FromValue>()))>
std::map<Key, ToValue> transform_map(const std::map<Key, FromValue>& _map,
    Transformer _tr) {
  std::map<Key, ToValue> res;
  std::for_each(_map.cbegin(), _map.cend(), 
      [&res, &_tr](const std::pair<const Key, FromValue>& kv) {
        res[kv.first] = _tr(kv.second);
      });
  return res;
}

int main ()
{
    std::map<int, double> m1 {{1, 1.5}, {2, 2.5}};

    auto m2 = transform_map(m1, [](double d){ return static_cast<int>(d); });

    for (auto& p : m1)
        std::cout << p.first << " " << p.second << std::endl;

    for (auto& p : m2)
        std::cout << p.first << " " << p.second << std::endl;
}

Upvotes: 4

Related Questions