Reputation: 316
Are there any differences between
template <typename ForwardIter,
typename Comp = std::less<typename std::iterator_traits<ForwardIter>::value_type>>
void select_sort(ForwardIter first, ForwardIter last, Comp comp = Comp())
{
for (; first != last; ++first)
{
auto iter = std::min_element(first, last, comp);
std::swap(*first, *iter);
}
}
and the simpler version
template <typename ForwardIter,
typename Comp = std::less<>>
void select_sort(ForwardIter first, ForwardIter last, Comp comp = Comp())
{
// Same as above
}
Both seem to work. Is it just a style issue? Or are the cases where one have to choose one or the other?
Upvotes: 1
Views: 99
Reputation: 41840
Both will work but they are different.
std::less<T>
is the most commonly use case. It's a class that have the operator()
overloaded. It is implemented in a similar way as this.
I omitted some special cases about pointers here, but it's only a naive implementation for the sake of simplicity.
template<typename T>
struct less {
constexpr bool operator()(const T &lhs, const T &rhs) const {
return lhs < rhs;
}
};
It's like a functor, but you choose which T
it will be. The advantage of this solution is that one can specialize std::less<T>
for special cases of one's code.
std::less<>
is different. It can compare object of any types, as long as the two types has operator<
overloaded. It act just like a generic lambda. It is implemented a bit like this:
template<>
struct less<void> {
template<typename T, typename U>
constexpr auto operator()(T&& lhs, U&& rhs) const
-> decltype(std::declval<T>() < std::declval<U>()) {
return std::forward<T>(lhs) < std::forward<U>(rhs);
}
};
As you can see, when you use std::less<>{}(a, b)
, it's really close to the same thing as if you wrote a < b
, and will work even with types that has a non-const operator<
. So this one is the best, as long as the classes you use have the operator<
overloaded.
Upvotes: 2
Reputation:
typename Comp = std::less<typename std::iterator_traits<ForwardIter>::value_type>
means that when Comp
is not specified, std::less<typename std::iterator_traits<ForwardIter>::value_type>
is used.
typename Comp = std::less<>
means that when Comp
is not specified, std::less<>
is used.
That's the exact difference. It doesn't mean that the compiler somehow deduces the template argument for std::less<>
. Instead, since the template std::less<T=void>
specifies a default value, that default value is used.
The template specialisation std::less<void>
is defined in such a way that it can generally be used in place of other std::less<T>
versions. They're not exactly the same thing, there are cases where you'd use one or the other. From your question title though, your question appears to be about the syntax of the default argument, not about std::less
specifically, so I'll skip the explanation of that.
Upvotes: 2