之间是否有任何差异
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);
}
}
和更简单的版本
template <typename ForwardIter,
typename Comp = std::less<>>
void select_sort(ForwardIter first, ForwardIter last, Comp comp = Comp())
{
// Same as above
}
两者似乎都有效。这只是一个风格问题吗?或者是必须选择其中一个的情况?
答案 0 :(得分:2)
typename Comp = std::less<typename std::iterator_traits<ForwardIter>::value_type>
表示如果未指定Comp
,则会使用std::less<typename std::iterator_traits<ForwardIter>::value_type>
。
typename Comp = std::less<>
表示如果未指定Comp
,则会使用std::less<>
。
这是确切的区别。这并不意味着编译器以某种方式推导出std::less<>
的模板参数。相反,由于模板std::less<T=void>
指定了默认值,因此使用该默认值。
模板特化std::less<void>
的定义方式通常可用于代替其他std::less<T>
版本。它们不完全相同,有些情况下你会使用其中一种。但是,从您的问题标题来看,您的问题似乎是关于默认参数的语法,而不是std::less
具体,所以我将跳过对此的解释。
答案 1 :(得分:2)
两者都有效,但它们不同。
std::less<T>
是最常见的用例。它是一个operator()
重载的类。它的实现方式与此类似。
我在这里省略了一些关于指针的特殊情况,但为了简单起见,它只是一个天真的实现。
template<typename T>
struct less {
constexpr bool operator()(const T &lhs, const T &rhs) const {
return lhs < rhs;
}
};
它就像一个仿函数,但你选择它将是T
。此解决方案的优点是可以专门针对某个代码的特殊情况std::less<T>
。
std::less<>
不同。它可以比较任何类型的对象,只要这两种类型有operator<
重载。它就像一个普通的lambda。实现有点像这样:
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);
}
};
正如您所看到的,当您使用std::less<>{}(a, b)
时,它与您编写a < b
的内容非常接近,并且即使对于具有非const的类型也是如此operator<
。所以这个是最好的,只要你使用的类有operator<
重载。