使用透明的std函数对象还需要写空尖括号吗?

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

使用class模板参数推导我们可以写成:

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 编译时没有警告。哪个编译器是正确的?

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

(强调我的)

When a function-style cast or declaration of a variable uses the name of a primary class template C without an argument list as the type specifier, deduction will proceed as follows:

  • If C is defined, for each constructor (or constructor template) Ci declared in the named primary template (if it is defined), a fictional function template Fi, is constructed, such that
    • template parameters of Fi are the template parameters of C followed (if Ci is a constructor template) by the template parameters of Ci (default template arguments are included too)
    • the function parameters of Fi are the constructor parameters
    • the return type of Fi is C followed by the template parameters of the class template enclosed in <>
  • If C is not defined or does not declare any constructors, an additional fictional function template is added, derived as above from a hypothetical constructor C()
  • In any case, an additional fictional function template derived as above from a hypothetical constructor C(C) is added, called the copy deduction candidate.

Template argument deduction and overload resolution is then performed for initialization of a fictional object of hypothetical class type, whose constructor signatures match the guides (except for return type) for the purpose of forming an overload set, and the initializer is provided by the context in which class template argument deduction was performed, except that the first phase of list-initialization (considering initializer-list constructors) is omitted if the initializer list consists of a single expression of type (possibly cv-qualified) U, where U is a specialization of C or a class derived from a specialization of C.

These fictional constructors are public members of the hypothetical class type. They are explicit if the guide was formed from an explicit constructor. If overload resolution fails, the program is ill-formed. Otherwise, the return type of the selected F template specialization becomes the deduced class template specialization.

给定std::greater(),应用隐式生成的演绎指南,最后选择附加的虚构函数。作为重载决议的结果,应用了默认参数 void,然后推导的类型将为 void。这意味着 std::greater() 应该与 std::greater<void>()std::greater<>().

相同

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

GCC 错误。已经有 bug report.

[dcl.type.simple]/2 说:

A type-specifier of the form typenameopt nested-name-specifieropt template-name is a placeholder for a deduced class type ([dcl.type.class.deduct]).

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

A placeholder for a deduced class type can also be used in the type-specifier-seq in the new-type-id or type-id of a new-expression, as the simple-type-specifier in an explicit type conversion (functional notation) ([expr.type.conv]), or as the type-specifier in the parameter-declaration of a template-parameter. A placeholder for a deduced class type shall not appear in any other context.

允许这样使用。


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