Search code examples
c++templatesc++11typestypename

Cryptic template template parameter error


I'm trying to create a function that gets the keys from a std::map or an std::unordered_map. I could use a simple overload, but first I'd love to know what's wrong with this code.

template<typename K, typename V, template<typename, typename> class TContainer>  
std::vector<K> getKeys(const TContainer<K, V>& mMap)
{
    std::vector<K> result;
    for(const auto& itr(std::begin(mMap)); itr != std::end(mMap); ++itr) result.push_back(itr->first);
    return result;
}

When calling it with an std::unordered_map, even specifying all template typenames manually, clang++ 3.4 says:

template template argument has different template parameters than its corresponding template template parameter.


Solution

  • The problem is that std::map and std::unordered_map are not in fact templates with two parameters. They are:

    namespace std {
        template <class Key, class T, class Compare = less<Key>,
                  class Allocator = allocator<pair<const Key, T>>>
        class map;
    
        template <class Key, class T, class Hash = hash<Key>,
                  class Pred = equal_to<Key>,
                  class Allocator = allocator<pair<const Key, T>>>
        class unordered_map;
    }
    

    Here's something similar that does work:

    template <typename K, typename... TArgs, template<typename...> class TContainer>
    std::vector<K> getKeys(const TContainer<K, TArgs...>& mMap)
    {
        std::vector<K> result;
        for (auto&& p : mMap)
            result.push_back(p.first);
        return result;
    }
    

    The version I would prefer:

    template <typename Container>
    auto getKeys2(const Container& mMap) -> std::vector<typename Container::key_type>
    {
        std::vector<typename Container::key_type> result;
        for (auto&& p : mMap)
            result.push_back(p.first);
        return result;
    }
    

    A demo program using both functions: http://ideone.com/PCkcu6