使用透明的std函数对象时,我们是否仍需要写空尖括号?

时间:2018-11-02 07:47:06

标签: c++ templates language-lawyer c++17 argument-deduction

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

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无需警告即可对其进行编译。哪个编译器是正确的?

2 个答案:

答案 0 :(得分:28)

GCC错误。已经有一个bug report

[dcl.type.simple]/2说:

  

格式为typename类型说明符 opt 嵌套名称说明符 < sub> opt template-name 是推导的类类型([dcl.type.class.deduct])的占位符。

[dcl.type.class.deduct]/2说:

  

推断出的类类型的占位符也可以在 new-type-id type-id < new-expression 的/ em>,作为 simple-type-specifier 的显式类型转换(功能符号)([expr。 type.conv]),或者作为 template-parameter parameter-declaration 中的 type-specifier 。推导类类型的占位符不得出现在任何其他上下文中。

允许这种使用。


[temp.arg]/4描述了语法错误,该错误是 template-id 所必需的,但没有<>。但是,这里std::greater不能解析为 template-id ,因此该段落不适用。

答案 1 :(得分:14)

Clang和MSVC是正确的。由于implicitly-generated deduction guides (since C++17)和默认模板参数的组合作用,因此该格式应正确。

(重点是我的)

  

当函数式强制转换或变量声明使用名称时   没有参数列表作为类型的主类模板C的类型   说明符,将进行以下推断:

     
      
  • 如果定义了C,则对于在命名的主模板(如果已定义)中声明的每个构造器(或构造器模板)Ci,   构造功能模板Fi,使得      
        Fi的
    • 模板参数是C的模板参数,后跟(如果Ci是构造函数模板)   of 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<>()相同。


顺便说一句:Gcc不能用std::greater()进行编译,但是std::greater{}std::greater g;很好,这可能是gcc的错误。