C++17 模板参数推导之谜

5
在C++17中,你可以这样做:
#include <iostream>
#include <algorithm>
#include <functional>

int main()
{
    double values[5] = { 1.1, 2.2, 3.3, 4.4, 5.5 };

    // Notice this:
    std::sort(values, values+5, std::greater());

    for(double v: values) std::cout << v << " ";
    std::cout << "\n";
}

您实际上不需要指定std::greater的模板参数。 它将自动推断为double。这非常好。
但是等等...怎么做到的?!?
没有任何东西告诉std::greater 模板参数应该是类型double。 它没有采用任何构造函数参数之类的东西。 而且std::sort()的声明明显是这样的:
template<class RandomIt, class Compare>
void sort(RandomIt first, RandomIt last, Compare comp);

所以它里面没有任何内容表明它应该是双倍的。

那么怎么办?


我在使用手机,所以可以抓住这个机会:它是std::greater<>,它具有一个operator()模板而不是固定类型。 - Quentin
2
可能是什么是透明比较器?的重复问题。简而言之,就是Quentin所说的。透明比较器不是一个类模板,而是它的运算符()是一个模板。 - Fureeish
1
我不同意这是一个重复的问题。链接的"duplicate"有一个关于透明比较器的好讨论,以及它们如何定义 - 但它并没有回答OP的问题 - "这段代码是如何工作的"。 - Marshall Clow
1
@DavisHerring 我认为有一个缺失的链接:有一个默认的模板参数并不能使模板参数列表 (<>) 可以省略。这实际上是 CTAD 的威力,而在“重复”的文章中没有提到。 - cpplearner
@cpplearner:很好,如果我们想的话,甚至可以从()<void>制定一个扣除指南,而不允许使用<>。 (对于函数没有这样的区别,这可能影响了我的分析。) - Davis Herring
显示剩余2条评论
1个回答

5

对于 std::greater,有两种不同的定义方式,一种需要模板参数类型,另一种则不需要。

您使用的是第二种定义方式。

以下是 std::greater 的定义方式(不包括像 constexprnoexcept 这样的修饰符和不同的返回类型):

template <typename T = void>
struct greater
{
    bool operator () (const T& x, const T& y) { return x > y; }
};

template <>
struct greater<void>
{
    template <typename T1, typename T2>
    bool operator () (const T1& x, const T2& y) { return x > y; }
    typedef void is_transparent;
};

是的,但是 greater() 怎么会到第二个呢? - Barry
好的,它不能是第一个 - 因为您没有提供模板参数; 所以它必须是第二个。 - Marshall Clow
糟糕。谢谢,戴维斯。已修复。 - Marshall Clow
@MarshallClow:cpplearner的观点(也可能是你的观点)是正确的:这里必须提到CTAD。 - Davis Herring
这个答案本身至少是无效的。我尝试了一下,当像“std :: sort(values,values + 5,greater())”这样使用它时,会出现错误“在'('标记之前缺少模板参数”。 显然,它期望它像“greater <>()”那样使用。 但是,就像我原来的问题所示,std :: greater不需要空括号。因此,我的问题仍然没有得到回答。 我还要反对将其标记为其他帖子的副本,因为另一个帖子也没有回答问题。 - Warp
糟糕,刚才我用的是gcc 7.1进行测试,这个代码出现了错误。看起来直到gcc 9才可以在不使用<>括号的情况下编译。 - Warp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接