I would like to write a specialised template function for iterators whose value type is a pair. My expectation is that this should match iterators of std::map.
In order to detect the 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):
Candidate template ignored: could not match 'enable_if' against '__map_iterator'
With no further explanation why enable if didn't match.
When inspecting the type of __map_iterator, it looks like it should match is_pair check.
It's better to move std::enable_if
to another default template argument, like so:
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 deduction, since ITR && itr
is now an universal reference.
Full 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
I figured it out, essentially it was: SFINAE working in return type but not as template parameter
So in 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 reference was required because i needed an actual reference to the value inside the map.
The const version of the check wasn't necessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With