Currently I try to write a function retrieveKeys()
which gives me the keys of a std::map
and stores it in some std::container
. The function shall be generic in two ways:
std::map
and std::unordered_map
as parameter type.std::vector
or std::deque
(the container has to supports a push_back()
method).Currently the use of this function works as follows:
std::unordered_map<int, int> testMap;
std::map<int, int> testMap2;
std::vector<int> keys1 = retrieveKeys<std::vector>(testMap);
std::deque<int> keys2 = retrieveKeys<std::deque>(testMap);
std::vector<int> keys3 = retrieveKeys<std::vector>(testMap2);
std::deque<int> keys4 = retrieveKeys<std::deque>(testMap2);
With the following function:
template<template<typename...> typename KeyContainer, typename... KeyContainer_Rest,
template<typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
inline KeyContainer<K, KeyContainer_Rest...> retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys;
}
It would be nice if I would not have to write the return type explicitly. But when I try something like
std::vector<int> keys1_ = retrieveKeys(testMap);
/*
error: no matching function for call to 'retrieveKeys'
std::vector<int> keys1_ = retrieveKeys(testMap);
^~~~~~~~~~~~
*/
I get the mentioned error when compiling with clang 3.6 (C++17).
So my question is: Is it possible to rewrite the function so that the return type can be reduced by the compiler?
Here again the complete code for easy copying:
#include <deque>
#include <vector>
#include <unordered_map>
#include <map>
template<template<typename...> typename KeyContainer, typename... KeyContainer_Rest,
template<typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
inline KeyContainer<K, KeyContainer_Rest...> retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys;
}
int main()
{
std::unordered_map<int, int> testMap;
std::map<int, int> testMap2;
std::vector<int> keys1 = retrieveKeys<std::vector>(testMap);
std::deque<int> keys2 = retrieveKeys<std::deque>(testMap);
std::vector<int> keys3 = retrieveKeys<std::vector>(testMap2);
std::deque<int> keys4 = retrieveKeys<std::deque>(testMap2);
//std::vector<int> keys1_ = retrieveKeys(testMap);
/*
error: no matching function for call to 'retrieveKeys'
std::vector<int> keys1_ = retrieveKeys(testMap);
^~~~~~~~~~~~
*/
}
template <typename K, typename M>
struct ReturnTypeDeducer
{
const M& map;
ReturnTypeDeducer(const M& m) : map(m) {}
template <template <typename...> typename KeyContainer, typename... KeyContainer_Rest>
operator KeyContainer<K, KeyContainer_Rest...>() &&
{
KeyContainer<K, KeyContainer_Rest...> keys;
for (const auto& m : map)
{
keys.push_back(m.first);
}
return keys;
}
};
template <template <typename...> typename MapContainer, typename K, typename V, typename... MapContainer_Rest>
inline ReturnTypeDeducer<K, MapContainer<K, V, MapContainer_Rest...>> retrieveKeys(const MapContainer<K, V, MapContainer_Rest...>& map)
{
return map;
}
int main()
{
std::unordered_map<int, int> testMap;
std::map<int, int> testMap2;
std::vector<int> keys1 = retrieveKeys(testMap);
std::deque<int> keys2 = retrieveKeys(testMap);
std::vector<int> keys3 = retrieveKeys(testMap2);
std::deque<int> keys4 = retrieveKeys(testMap2);
}