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.