¿El tipo de devolución es parte de la firma de la función?

En C ++, ¿el tipo de devolución se considera parte de la firma de la función? y no se permite la sobrecarga con solo el tipo de devolución modificado.

Las funciones normales no incluyen el tipo de devolución en su firma.

( nota : he reescrito esta respuesta, y los comentarios a continuación no se aplican a esta revisión – vea el historial de edición para más detalles).

Introducción

Sin embargo, el asunto sobre funciones y declaraciones de funciones en el Estándar es complicado. Hay dos capas que deben considerarse:

  • Declaraciones
  • Entidades

La llamada statement de función puede declarar una entidad de función o una entidad de plantilla. Si se declara una entidad de función, entonces tiene que ver con una especialización explícita de una plantilla de función (con todos los argumentos especificados), o una statement de una función ordinaria. Si se declara una entidad de plantilla, se declara una plantilla de función principal o una especialización explícita donde no se especifican algunos argumentos. (Esto es muy similar a la relación entre “statement de objeto” y objetos o referencias: el primero puede declarar un objeto o una referencia, ¡así que una statement de objeto no necesariamente declara un objeto!).

El estándar define la firma de una función para incluir lo siguiente en 1.3.10 :

Los tipos de sus parámetros y, si la función es un miembro de la clase, los cv-calificadores (si los hay) sobre la función misma y la clase en la que se declara la función miembro. La firma de una especialización de plantilla de función incluye los tipos de sus argumentos de plantilla. (14.5.5.1)

Falta el tipo de devolución en esta definición, que es parte de la firma de una especialización de plantilla de función (es decir, una statement de función que declara una función que es una especialización de una plantilla), como se señala en 14.5.5.1 (C ++ reciente) 0x documentos de trabajo corregidos que ya mencionan el tipo de devolución en 1.3.10 también):

La firma de una especialización de plantilla de función consiste en la firma de la plantilla de función y de los argumentos de la plantilla real (ya sea explícitamente especificado o deducido).

La firma de una plantilla de función consiste en su firma de función, su tipo de devolución y su lista de parámetros de plantilla.

Entonces, ¿qué contiene exactamente una firma, otra vez?

Entonces, cuando preguntamos sobre la firma de una función , tenemos que dar dos respuestas:

  • Para las funciones que son especializaciones de plantillas de funciones, la firma incluye el tipo de devolución.
  • Para las funciones que no son especializaciones, el tipo de devolución no es parte de la firma.

Tenga en cuenta, sin embargo, que el tipo de devolución, en cualquier caso, es una parte importante del tipo de una función. Es decir, lo siguiente no es válido:

 void f(); int (*pf)() = &f; // different types! 

¿Cuándo se invalida una sobrecarga si solo difiere el tipo de devolución?

Los principales comstackdores actualmente rechazan el siguiente código:

 int f(); double f(); // invalid 

Pero acepta el siguiente código:

 template int f(); template double f(); // invalid? 

Sin embargo, el Estándar prohíbe una statement de función que solo difiere en el tipo de devolución (cuando se define cuándo una sobrecarga es válida y cuándo no). Sin embargo, no define con precisión lo que “se diferencia solo por el tipo de devolución”.


Referencias de párrafo estándar:

  • Cuándo se puede sobrecargar una statement de función: 13.1
  • Qué es una statement de función: 7/2 y 7/5
  • Cuál es la firma de una plantilla de función / especialización: 14.5.5.1

A modo de referencia, esto es lo que dice el borrador n3000 de C ++ 0x más reciente sobre “firma” en 1.3.11 , que es mucho más completo en su cobertura de los diferentes tipos de entidades:

el nombre y la lista de tipos de parámetros (8.3.5) de una función, así como la clase o el espacio de nombres de los que es miembro. Si una plantilla de función o función es un miembro de la clase, su firma incluye adicionalmente los calificativos de cv (si los hay) y el calificador de ref (si corresponde) en la plantilla de funciones o funciones. La firma de una plantilla de función incluye, además, su tipo de devolución y su lista de parámetros de plantilla. La firma de una especialización de plantilla de función incluye la firma de la plantilla de la que es una especialización y sus argumentos de plantilla (explícitamente especificados o deducidos). [Nota: las firmas se utilizan como base para la creación y el enlace de nombres. – nota final]

Depende si la función es una plantilla de función o no.

En las plantillas de C ++, las guías completas , Jusuttis proporciona una definición diferente de la dada en el estándar de C ++, pero con consecuencias equivalentes:

Definimos la firma de una función como la siguiente información:

  1. El nombre no calificado de la función
  2. El ámbito de clase o espacio de nombre de ese nombre, y si el nombre tiene un enlace interno, la unidad de traducción en la que se declara el nombre
  3. La const , volatile o const volatile cualificación de la función
  4. Los tipos de los parámetros de la función
  5. su tipo de devolución, si la función se genera a partir de una plantilla de función
  6. Los parámetros de la plantilla y los argumentos de la plantilla , si la función se genera a partir de una plantilla de función

Como lo sugirió litb , vale la pena aclarar por qué el tipo de devolución es parte de la firma de una función de plantilla.

Las funciones pueden coexistir en un progtwig si tienen firmas distintas.

. Dicho eso, si el tipo de devolución es un parámetro de plantilla:

 template  T foo(int a) {return T();} 

Es posible crear una instancia de dos funciones que solo difieren en el tipo de devolución:

 foo(0); foo(0); 

No solo: como correctamente informó litb , también es posible sobrecargar dos funciones de plantilla, que difieren solo en el tipo de devolución, incluso si el tipo de devolución no es un nombre dependiente. Aquí está su ejemplo:

 template int foo(T) {} template bool foo(T) {} // at the instantiation point it is necessary to specify the cast // in order not to face ambiguous overload ((int(*)(char))foo)('a'); 

Son suficientes como parte del tipo en que puede sobrecargar funciones basadas en tipos de punteros de función que difieren solo por tipo de devolución:

 int IntFunc() { return 0; } char CharFunc() { return 0; } void FuncFunc(int(*func)()) { cout << "int\n"; } void FuncFunc(char(*func)()) { cout << "char\n"; } int main() { FuncFunc(&IntFunc); // calls void FuncFunc(int_func func) FuncFunc(&CharFunc); // calls void FuncFunc(char_func func) }