函数模板语法的默认模板参数

时间:2017-01-07 20:58:24

标签: c++ templates

之间是否有任何差异
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
}

两者似乎都有效。这只是一个风格问题吗?或者是必须选择其中一个的情况?

2 个答案:

答案 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<重载。