c++ - significan - ¿Todavía necesitamos escribir los corchetes de ángulo vacíos cuando usamos objetos de función estándar transparentes?
que significan los parentesis y corchetes en matematicas (2)
Con la deducción de argumento de plantilla de clase podemos escribir:
std::less Fn;
Sin embargo, G ++ 8.2 rechaza este código:
#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());
}
emitiendo el siguiente error:
error: cannot deduce template arguments for ''greater'' from ()
Clang ++ 7.0 y MSVC 15.8.0 lo compilan sin advertencias. ¿Qué compilador tiene razón?
Clang y MSVC son correctos. Esto debería estar bien formado debido al efecto de combinación de las guías de deducción generadas implícitamente (desde C ++ 17) y el argumento de la plantilla predeterminada.
(énfasis mío)
Cuando una conversión de estilo de función o una declaración de una variable usa el nombre de una plantilla de clase primaria C sin una lista de argumentos como el especificador de tipo, la deducción se realizará de la siguiente manera:
- Si se define C, para cada constructor (o plantilla de constructor) Ci declarada en la plantilla primaria nombrada (si está definida), se construye una plantilla de función ficticia Fi, de manera que
- los parámetros de plantilla de Fi son los parámetros de plantilla seguidos de C (si Ci es una plantilla de constructor) por los parámetros de plantilla de Ci ( también se incluyen los argumentos de la plantilla por defecto )
- Los parámetros de función de Fi son los parámetros del constructor.
- el tipo de retorno de Fi es C seguido de los parámetros de plantilla de la plantilla de clase incluida en <>
- Si C no está definido o no declara ningún constructor, se agrega una plantilla de función ficticia adicional, derivada como arriba de un constructor hipotético C ()
- En cualquier caso, se agrega una plantilla de función ficticia adicional derivada como anteriormente de un constructor hipotético C (C), denominada candidato a deducción de copia.
La deducción de los argumentos de la plantilla y la resolución de sobrecarga se realizan para la inicialización de un objeto ficticio de tipo de clase hipotética, cuyas firmas de constructor coinciden con las guías (excepto para el tipo de retorno) con el propósito de formar un conjunto de sobrecarga, y el inicializador lo proporciona el contexto qué clase de clase se realizó la deducción de argumentos, excepto que la primera fase de la lista de inicialización (considerando los constructores de lista de inicializadores) se omite si la lista de inicializadores consiste en una única expresión de tipo U (posiblemente calificada como CV) U, donde U es una especialización de C o una clase derivada de una especialización de C.
Estos constructores ficticios son miembros públicos del tipo de clase hipotética. Son explícitos si la guía se formó a partir de un constructor explícito. Si falla la resolución de sobrecarga, el programa está mal formado. De lo contrario, el tipo de retorno de la especialización de plantilla F seleccionada se convierte en la especialización de plantilla de clase deducida.
Dado std::greater()
, la guía de deducción generada implícitamente se aplica y la función de ficción adicional se selecciona por fin. Como resultado de la resolución de sobrecarga, se aplica el argumento por defecto void
, entonces el tipo deducido será void
. Eso significa que std::greater()
debería ser igual que escribir std::greater<void>()
o std::greater<>()
.
BTW: Gcc no compila con std::greater()
, pero std::greater{}
o std::greater g;
están bien, podría ser el error de gcc.
GCC está equivocado Ya hay un informe de error .
[dcl.type.simple]/2 dice:
Un especificador de tipo de la forma
typename
opt nombre-anidado-especificador opt template-name es un marcador de posición para una clase de clase deducida ([dcl.type.class.deduct]).
Y [dcl.type.class.deduct]/2 dice:
Un marcador de posición para un tipo de clase deducido también se puede usar en el tipo-especificador-seq en el nuevo tipo-id o tipo-id de una nueva expresión , como el simple-tipo-especificador en una conversión de tipo explícita (notación funcional ) ([expr.type.conv]), o como el especificador de tipo en la declaración de parámetro de un parámetro de plantilla . Un marcador de posición para un tipo de clase deducido no aparecerá en ningún otro contexto.
Se permite tal uso.
[temp.arg]/4 describe el error de sintaxis de que se requiere una ID de plantilla pero no hay <>
. Sin embargo, aquí std::greater
no se resuelve como una plantilla-id, por lo que el párrafo no se aplica.