当使用透明的std函数对象时,我们还需要写空的尖括号吗

Do we still need to write the empty angle brackets when using transparent std function objects?

本文关键字:透明 std 函数 对象 我们      更新时间:2023-10-16

通过类模板参数推导,我们可以编写:

std::less Fn;

然而,G++8.2拒绝了这个代码:

#include <algorithm>
#include <vector>
#include <functional>
int main()
{
std::vector v= { 1, 3, 2, 7, 5, 4 };
std::sort(v.begin(),v.end(),std::greater());
}

发出以下错误:

error: cannot deduce template arguments for 'greater' from ()

Clang++7.0和MSVC 15.8.0在没有警告的情况下编译它。哪个编译器是对的?

GCC错误。已经有一个错误报告。

[dcl.type.simple]/2表示:

形式为typenameopt嵌套名称说明符>opt模板名称类型说明符是推导类类型([dcl.type.class.dexecte](的占位符。

并且[dcl.type.class.dexecute]/2说:

推导类类型的占位符也可以用于新表达式类型id中的type说明符seq在显式类型转换(函数表示法(中用作简单类型说明符([expr.type.conv](,或在模板参数参数声明中作为类型说明符。推导类类型的占位符不应出现在任何其他上下文中。

允许这样的使用。


[temp.arg]/4描述了语法错误,即需要模板id,但没有<>。然而,此处std::greater未解析为模板id,因此该段不适用。

Clang和MSVC是正确的。由于隐式生成的推导指南(自C++17以来(和默认模板参数的组合效应,这应该是很好的形式。

(重点矿井(

当函数样式转换或变量声明使用名称时没有参数列表作为类型的主类模板C的说明符,推导过程如下:

  • 如果定义了C,则对于命名的主模板(如果定义了它(中声明的每个构造函数(或构造函数模板(Ci构建函数模板Fi,使得
    • Fi的模板参数是C的模板参数,后面是模板参数(如果Ci是构造函数模板(Ci的(也包括默认模板参数(
    • Fi的函数参数是构造函数参数
    • Fi的返回类型是C,后跟<>中包含的类模板的模板参数
  • 如果C没有定义或没有声明任何构造函数,则会添加一个额外的虚构函数模板,该模板如上所述从一个假设的构造函数C((
  • 在任何情况下,都会添加一个从假设构造函数C(C(派生的附加虚构函数模板,称为副本扣除候选者

然后执行模板参数推导和重载解析对于假设类类型的虚构对象的初始化,其构造函数签名与指南匹配(返回类型除外(为了形成重载集,初始化器是由类模板参数推导所在的上下文提供执行,除了列表初始化的第一阶段如果初始值设定项列表由类型为(可能cv限定(U,其中U是C的专业化或派生的类来自C.的一个专业

这些虚构的构造函数是假设的公共成员类类型。如果指南是由明确的构造函数。如果过载解析失败,则表示程序格式不正确。否则,所选F模板专用化的返回类型成为推导出的类模板专门化。

给定std::greater(),应用隐式生成的推导指南,最后选择附加的虚构函数。作为重载解析的结果,应用默认参数void,则推导出的类型将为void。这意味着std::greater()应该与写入std::greater<void>()std::greater<>()相同。


BTW:Gcc不使用std::greater()编译,但std::greater{}std::greater g;可以,这可能是Gcc的错误