Enable_if check if the value type of the iterator is a pair

I would like to write a specialized template function for iterators whose value type is a pair. I expect this to match std :: map iterators.

To find a pair:

template <typename>
struct is_pair : std::false_type
{ };

template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type
{ };

// also tried this, but it didn't help
template <typename T, typename U>
struct is_pair<std::pair<const T, U>> : std::true_type
{ };

      

Then I use enable_if in the function declaration:

template<class ITR>
decltype(auto) do_stuff(
        std::enable_if<is_pair<typename ITR::value_type>::value, ITR> itr) {
    //access of itr->second ok.
}

      

However, when I use this function with a map iterator, I get the following error messages from clang (Xcode 8.3):

Applicant template ignored: Could not match "enable_if" with "__map_iterator"

Without further explanation, why enable if not the same.

When checking the type of __map_iterator, it looks like it should match the is_pair check.

+3


source to share


2 answers


Better to move std::enable_if

to another default template argument like:

template<class ITR, typename = typename std::enable_if<is_pair<typename ITR::value_type>::value, ITR>::type>
decltype(auto) do_stuff(ITR && itr) {
    //access of itr->second ok.
}

      

This will not block argument output as ITR && itr

it is now a generic reference.

Complete example:



#include <type_traits>
#include <utility>
#include <map>

template <typename>
struct is_pair : std::false_type
{ };

template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type
{ };


template<class ITR, typename = typename std::enable_if<is_pair<typename ITR::value_type>::value, ITR>::type>
decltype(auto) do_stuff(ITR && itr) {
    //access of itr->second ok.
}

int main()
{
    std::map<int, int> foo{
        { 1, 2 },
        { 3, 4 },
    };

    do_stuff(foo.begin());
    return 0;
}

      


Live on gcc.godbolt.org

+4


source


I figured out basically this: SFINAE works in reverse, but not as a template parameter

So at the end I used this signature:

template<class ITR>
typename std::enable_if_t<is_pair<typename ITR::value_type>::value, ITR>::value_type::second_type& get_value_from_iterator(ITR itr)

      



The link was required because I need an actual reference to the value inside the map.

The configuration version of the check is not needed.

+1


source







All Articles