I want to write a type-safe function in C++ that composes an arbitrary number of maps. I approached by writing a helper function point
that computes the application of the composition at a point–
template <typename K>
const K& point(const K& k) {
return k; // recursive base-case.
}
template<typename K, typename V, typename ... Ts>
auto point(const K& k, const std::map<K, V>& map, Ts... maps) {
return point(map.at(k), maps...);
}
which makes the logic of compose
straightforward:
template <typename K, typename V, typename ... Ts>
auto compose(const std::map<K, V>& map, Ts... maps) {
using U = typename std::result_of<point(V, Ts...)>::type; // <- problem
std::map<K, U> composition;
for (const auto& [k, v] : map)
composition[k] = point(v, maps...);
return composition;
}
My only issue is deducing U
, the value-type of the resulting map . I am sure that std::result_of
is an appropriate approach, but I get error: 'V' does not refer to a value
with the code above. I also tried using decltype(point<V, Ts...>())
but that gives error: no matching function for call to 'point'
.
Example usage:
std::map<int, std::string> m1;
m1[0] = "a";
m1[1] = "b";
std::map<std::string, float> m2;
m2["a"] = 3.0;
m2["c"] = 4.0;
std::map<float, std::string> m3;
m3[3.0] = "three";
m3[4.0] = "four";
auto composition = compose(m1, m2, m3);
Here is my final version using the type deduction provided by @NathanOliver and using std::optional
to omit any element that cannot be fully mapped through the composition.
template<typename K>
const K& point(const K& k) { return k; }
template<typename K, typename V, typename ... Ts>
auto point(const K &k, const std::map<K, V>& map, Ts... maps) {
return map.find(k) == map.end() ?
std::nullopt :
std::optional(point(map.at(k), maps...));
}
template<typename K, typename V, typename ... Ts>
auto compose(const std::map<K, V>& map, Ts... maps) {
using U = typename decltype(point(std::declval<V>(), std::declval<Ts>()...))::value_type;
std::map<K, U> composition;
for (const auto& [k, v] : map) {
auto result = point(v, maps...);
if (result.has_value())
composition[k] = result.value();
}
return composition;
}