Нужно ли нам писать пустые угловые скобки при использовании прозрачных объектов функции std? - PullRequest
0 голосов
/ 02 ноября 2018

С выводом аргумента шаблона класса мы можем написать:

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 голосов
/ 02 ноября 2018

GCC не так. Уже есть отчет об ошибке .

[dcl.type.simple] / 2 говорит:

A спецификатор типа формы typename opt спецификатор вложенного имени opt template-name - это заполнитель для выведенного типа класса ([dcl.type.class.deduct]).

И [dcl.type.class.deduct] / 2 говорит:

Заполнитель для выведенного типа класса также можно использовать в спецификатор типа-seq в new-type-id или type-id new-expression , в качестве спецификатора простого типа в явном преобразовании типов (функциональная запись) ([expr.type.conv]), или как спецификатор типа в объявлении параметра шаблона-параметра . Заполнитель для выведенного типа класса не должен появляться ни в каком другом контексте.

Такое использование разрешено.


[temp.arg] / 4 описывает синтаксическую ошибку , что требуется template-id , но нет <>. Однако здесь std::greater не разрешается как template-id , поэтому параграф не применяется.

0 голосов
/ 02 ноября 2018

Clang и MSVC верны. Это должно быть правильно сформировано из-за комбинированного эффекта неявно генерируемых руководств по выводам (начиная с C ++ 17) и аргумента шаблона по умолчанию.

(акцент мой)

Когда приведение типа функции или объявление переменной использует имя шаблона первичного класса C без списка аргументов в качестве типа спецификатор, вычет будет происходить следующим образом:

  • Если C определен, для каждого конструктора (или шаблона конструктора) Ci, объявленного в названном первичном шаблоне (если он определен), вымышленный Функциональный шаблон Fi, построен так, что
    • параметры шаблона Fi - это параметры шаблона C, за которыми следуют (если Ci является шаблоном конструктора) параметры шаблона. Ci ( также включены аргументы шаблона по умолчанию )
    • Параметры функции Fi являются параметрами конструктора
    • тип возврата Fi - C, за которым следуют параметры шаблона шаблона класса, заключенного в <>
  • Если C не определен или не объявляет никаких конструкторов, добавляется дополнительный шаблон вымышленной функции, полученный как указано выше из гипотетический конструктор C ()
  • В любом случае добавляется дополнительный шаблон вымышленной функции, полученный, как указано выше, из гипотетического конструктора C (C), называемый копией кандидат на вычет.

Затем выполняется вывод аргумента шаблона и разрешение перегрузки. для инициализации вымышленного объекта типа гипотетического класса, чьи подписи конструктора соответствуют направляющим (за исключением типа возврата) с целью формирования набора перегрузки, и инициализатор обеспечивается контекстом, в котором вычет аргумента шаблона класса был выполняется, за исключением того, что первый этап инициализации списка (с учетом конструкторов списка инициализатора) опускается, если список инициализаторов состоит из одного выражения типа (возможно cv-qualified) 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...