I want to use the SFINAE principle to check whether the instantiated template is a random access iterator. To do this, I used std::enable_if, but the compiler throws an error:
Cannot combine with previous 'type-name' declaration specifier
How can I fix it? I really need help to figure it out.
template<class RandomAccessIterator, class Compare>
typename std::enable_if<std::is_same<std::random_access_iterator_tag, RandomAccessIterator>::value>
void quick_sort(RandomAccessIterator first, RandomAccessIterator last, Compare compare) {
sorting(first, last, 0, last - first - 1, compare);
}
CodePudding user response:
Two issues I see:
You're writing
std::enable_if<>instead ofstd::enable_if<>::type, which is probably not what you meant to do.(The cause of the error) You have two return types:
std::enable_if<>andvoid. You can only have one return type.
std::enable_if has a second optional type parameter that is the the type of std::enable_if<>::type. This is set by default to void so your return type will already be void from std::enable_if<>::type. However since you're putting enable_if in the return type I'd recommend you explicitly specify that the return type be void.
So the solution to your issue would look something like this:
template <class RandomAccessIterator, class Compare>
typename std::enable_if<
std::is_same<std::random_access_iterator_tag, RandomAccessIterator>::value,
void
>::type quick_sort(RandomAccessIterator first, RandomAccessIterator last, Compare compare) {
sorting(first, last, 0, last - first - 1, compare);
}
Alternatively you could use std::enable_if in a template parameter:
template <
class RandomAccessIterator,
class Compare,
typename std::enable_if<
std::is_same<std::random_access_iterator_tag, RandomAccessIterator>::value,
std::nullptr_t
>::type = nullptr
>
void quick_sort(RandomAccessIterator first, RandomAccessIterator last, Compare compare) {
sorting(first, last, 0, last - first - 1, compare);
}
CodePudding user response:
In addition to the technical issues mentioned in this answer, your approach will simply not work at all.
std::is_same<std::random_access_iterator_tag, RandomAccessIterator>::value will never evaluate as true, because an iterator is not an iterator tag. You need to use tag dispatching via std::iterator_traits, not SFINAE, to determine if the iterators being passed in are random-access or not.
See the example on cppreference: https://en.cppreference.com/w/cpp/iterator/iterator_tags
Try this instead:
template<class Iter, class Compare>
void quick_sort_impl(Iter first, Iter last, Compare compare, std::random_access_iterator_tag) {
sorting(first, last, 0, last - first - 1, compare);
}
template<class Iter, class Compare>
void quick_sort(Iter first, Iter last, Compare compare) {
quick_sort_impl(first, last, compare, typename std::iterator_traits<Iter>::iterator_category());
}
This way, if you try to call quick_sort() with iterators that are not random access, you will get a compiler error due to a missing quick_sort_impl() overload for non-random iterator tags. If you want to implement sorting for other types of iterators, simply overload quick_sort_impl() for the other types of iterator tags as needed.
