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

8 minutos de lectura

¿El tipo de retorno es parte de la firma de
yesraaj

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

¿El tipo de retorno es parte de la firma de
Johannes Schaub – litb

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; consulte el historial de edición para obtener más detalles).

Introducción

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

  • Declaraciones
  • Entidades

La llamada declaración 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 declaración de una función ordinaria. Si se declara una entidad de plantilla, entonces está declarando una plantilla de función principal o una especialización explícita en la que no se especifican algunos argumentos. (Esto es muy similar a la relación de “declaración de objeto” y objetos o referencias: el primero puede declarar un objeto o una referencia. Entonces, un declaración de objeto ¡no necesariamente puede declarar 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 miembro de una clase, los calificadores cv- (si los hay) en 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 retorno en esta definición, que es parte de la firma de una especialización de plantilla de función (es decir, una declaración de función que declara una función que es una especialización de una plantilla), como lo señala 14.5.5.1 (Los documentos de trabajo recientes de C++ 0x arreglaron que ya mencionar el tipo de retorno en 1.3.10 también):

La firma de una especialización de plantilla de función consta de la firma de la plantilla de función y de los argumentos de plantilla reales (ya sea que se especifiquen o deduzcan explícitamente).

La firma de una plantilla de función consta de su firma de función, su tipo de retorno y su lista de parámetros de plantilla.

Entonces, ¿qué contiene exactamente una firma, de nuevo?

Entonces, cuando preguntamos sobre la firma de un funcióntenemos que dar dos respuestas:

  • Para las funciones que son especializaciones de plantillas de funciones, la firma incluye el tipo de valor devuelto.
  • Para las funciones que no son especializaciones, el tipo de valor devuelto no forma parte de la firma.

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

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

¿Cuándo es inválida una sobrecarga si solo difiere el tipo de retorno?

Los principales compiladores actualmente rechazan el siguiente código:

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

Pero acepta el siguiente código:

template<typename T> int f();
template<typename T> double f(); // invalid?

sin embargo, el El estándar prohíbe una declaración de función que solo difiera en el tipo de retorno (al definir cuándo una sobrecarga es válida y cuándo no). Sin embargo, no define con precisión qué significa “difiere solo por el tipo de devolución”.


Referencias de párrafo estándar:

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

Como referencia, esto es lo que dice el borrador n3000 de C++0x más reciente sobre “firma” en 1.3.11que es mucho más completa 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 del que es miembro. Si una función o plantilla de función es un miembro de clase, su firma incluye adicionalmente los calificadores cv (si los hay) y el calificador ref (si los hay) en la función o plantilla de función en sí. La firma de una plantilla de función incluye además su tipo de retorno 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 (ya sea explícitamente especificados o deducidos). [ Note: Signatures are used as a basis for name mangling and linking. — end note ]

  • ¿Puede explicar esta llamada emitida a la función static_cast

    (caracter)>(foo)(‘T’);

    – yesraaj

  • 18 de noviembre de 2008 a las 7:04

    yesraaj: foo no será suficiente, ya que hay dos funciones que encajarían, con dos tipos de devolución diferentes. estos tienen tipos void(char) e int(char) después de que el compilador coloca la plantilla en lugar de T.

    – Johannes Schaub – litb

  • 18 de noviembre de 2008 a las 11:31Ahora, para obtener la dirección correcta, debe darle una pista al compilador. Necesita el tipo del puntero. Eso se puede hacer usando un yeso. Podrías haber hecho (int()(char)) (foo) en lugar de static_cast

    )(char)> (foo)

    – Johannes Schaub – litb

  • 18 de noviembre de 2008 a las 11:37

    pero generalmente es mejor usar static_cast, ya que restringe en gran medida el dominio de tipos a los que puede enviar. Ver este stackoverflow.com/questions/103512/…

    – Johannes Schaub – litb

  • 18 de noviembre de 2008 a las 11:40

    ahora bien, un reparto no es la única posibilidad de contextualizar. también puedes hacer int(*ptr)(char) = foo; ptr(‘T’); y el compilador sabe que desea la función de plantilla que devuelve int. entonces lo llamas.

    – Johannes Schaub – litb

¿El tipo de retorno es parte de la firma de
18 de noviembre de 2008 a las 11:43

Nicola Bonelli Depende si la función es una plantilla de función

O no. EnPlantillas de C++: las guías completas

Jusuttis proporciona una definición diferente a la dada en el estándar C++, pero con consecuencias equivalentes:

  1. Definimos la firma de una función como la siguiente información: los nombre no calificado
  2. de la función los clase o espacio de nombres
  3. alcance de ese nombre, y si el nombre tiene un vínculo interno, la unidad de traducción en la que se declara el nombre constlos volatile, const volatile o
  4. calificación de la función los tipos
  5. de los parámetros de la función su regresoescribe
  6. si la función se genera a partir de una plantilla de función los parámetros de la plantilla y elargumentos de plantilla

si la función se genera a partir de una plantilla de función Como litb

sugerido, 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 programa si tienen firmas distintas.

template <typename T>
T foo(int a)
{return T();}

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

foo<int>(0);
foo<char>(0);

es posible instanciar dos funciones que difieren solo en el tipo de retorno: No sólo: como acertadamente informalitb

template<class T> int foo(T)
{}

template<class T> bool foo(T)
{}

// at the instantiation point it is necessary to specify the cast
// in order not to face ambiguous overload

((int(*)(char))foo<char>)('a'); 

  • , también es posible sobrecargar dos funciones de plantilla, que difieren solo en el tipo de retorno, incluso si el tipo de retorno no es un nombre dependiente. Aquí está su ejemplo:

    Dice en una nota al pie “Esta definición es diferente de la dada por el estándar C++, pero sus consecuencias son equivalentes”. Por lo tanto, esa es la definición de algún libro, pero no de C++.

    – Johannes Schaub – litb

  • 15 de noviembre de 2008 a las 11:37

    Si lee esta publicación detenidamente, puede encontrar la nota al pie en la segunda oración 🙂

    – Nicola Bonelli

  • 15 de noviembre de 2008 a las 11:40

    El punto que querían hacer es que las plantillas de funciones pueden coexistir así en el mismo ámbito: template int foo(T); template bool foo(T); int principal() { ((int

    (char))foo)(‘a’); }

  • – Johannes Schaub – litb

    15 de noviembre de 2008 a las 11:42

    Creo que tu respuesta puso algo de luz en la oscuridad. así que voté 🙂

  • – Johannes Schaub – litb

    15 de noviembre de 2008 a las 12:11

    Cambié mi respuesta para reflejar mi interpretación más reciente del estándar.

– Johannes Schaub – litb

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)
}

18 de diciembre de 2009 a las 12:03

Son una parte suficiente del tipo que puede sobrecargar funciones en función de los tipos de puntero de función que difieren solo por el tipo de retorno:

template <typename T>
T f(double x, T dummy) {
    T output;
    output = x * 2;
return output;
}

Encuentro una forma útil de hacer implícitamente que el tipo de retorno sea parte de una firma es incluir un argumento ‘ficticio’ en las entradas.

f(2, double(1))

Por ejemplo:

f(2, int(1))

En este caso, si desea una salida doble, ingrese:

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad