Template parameter deduction problem with C++ concepts and `std::is_same`

288 Views Asked by At

If I try to write a function that is restricted by a concept to either std::map and std::unordered_map with Key keys and Element elements it fails to deduce the Key type in the following piece of code.

template<typename A, typename B>
concept is_same_as = std::is_same<A, B>::value;

template<typename T, typename Key, typename Element>
concept map_type_of =
    is_same_as<T, std::map<Key, Element>> ||
    is_same_as<T, std::unordered_map<Key, Element>>;

template <typename T, typename Key, typename Element>
requires map_type_of<T,Key,Element>
inline std::list<Key> map_extract_keys(T const& a) {
    std::list<Key> output;
    for (auto const& element : a) {
        output.push_back(element.first);
    }
    return output;
}

std::map<std::string, int> map_example;

auto keys = map_extract_keys(map_example);

The actual error it gives:

candidate: ‘template<class T, class Key, class Element>  requires  map_type_of<T, Key, Element> std::__cxx11::list<Key> map_extract_keys(const T&)’
inline std::list<Key> map_extract_keys(T const& a) {

note:   template argument deduction/substitution failed:
note:   couldn’t deduce template parameter ‘Key’

Is there any way to allow that automatic deduction?

2

There are 2 best solutions below

0
On BEST ANSWER

Your map_type_of concept doesn't help you over a simpler concept

template<typename T>
concept is_map = std::ranges::range<T> 
              && std::semiregular<typename T::key_type> 
              && std::semiregular<typename T::mapped_type>;

template <typename T>
requires is_map<T>
inline std::list<typename T::key_type> map_extract_keys(T const& a) {
    std::list<typename T::key_type> output;
    for (auto const& [key, value] : a) {
        output.push_back(key);
    }
    return output;
}

Which, as a bonus, allows things like boost::bimap<...>::left_map etc

0
On

With minimal changes to your code I guess you could do:

template <template <typename, typename> class T, typename K, typename E>
requires map_type_of<T<K,E>, K, E>
inline auto map_extract_keys(T<K,E> const& a) {
    std::list<K> output;
    for (auto const& element : a) {
        output.push_back(element.first);
    }
    return output;
}