web-dev-qa-db-fra.com

Le type de retour fait-il partie de la signature de fonction?

En C++, le type de retour est-il considéré comme faisant partie de la signature de fonction? et aucune surcharge n'est autorisée avec juste le type de retour modifié.

65
yesraaj

Les fonctions normales n'incluent pas le type de retour dans leur signature.

( note : j'ai réécrit cette réponse, et les commentaires ci-dessous ne s'appliquent pas à cette révision - voir l'historique des modifications pour plus de détails).

Introduction

Cependant, la question des fonctions et des déclarations de fonctions dans la norme est compliquée. Il y a deux couches à considérer:

  • Déclarations
  • Entités

La soi-disant déclaration de fonction peut déclarer une entité de fonction ou une entité de modèle. Si une entité de fonction est déclarée, alors vous devez soit faire une spécialisation explicite d'un modèle de fonction (avec tous les arguments spécifiés), soit une déclaration d'une fonction ordinaire. Si une entité de modèle est déclarée, vous déclarez un modèle de fonction principale ou une spécialisation explicite où certains arguments ne sont pas spécifiés. (Ceci est très similaire à la relation entre "déclaration d'objet" et objets ou références: les premiers peuvent déclarer soit un objet soit une référence. Donc, une déclaration d'objet ne déclare pas nécessairement un objet!).

La norme définit la signature d'une fonction pour inclure les éléments suivants à 1.3.10:

Les types de ses paramètres et, si la fonction est un membre de classe, les qualificatifs cv (le cas échéant) sur la fonction elle-même et la classe dans laquelle la fonction membre est déclarée. La signature d'une spécialisation de modèle de fonction inclut les types de ses arguments de modèle. (14.5.5.1)

Il manque le type de retour dans cette définition, qui fait partie de la signature d'une spécialisation de modèle de fonction (c'est-à-dire une déclaration de fonction qui déclare une fonction qui est un spécialisation d'un modèle), comme le souligne 14.5.5.1 (les récents documents de travail C++ 0x corrigeaient déjà le type de retour dans 1.3.10 aussi):

La signature d'une spécialisation de modèle de fonction se compose de la signature du modèle de fonction et des arguments de modèle réels (qu'ils soient explicitement spécifiés ou déduits).

La signature d'un modèle de fonction se compose de sa signature de fonction, de son type de retour et de sa liste de paramètres de modèle.

Alors, que contient exactement une signature?

Ainsi, lorsque nous posons des questions sur la signature d'une fonction , nous devons donner deux réponses:

  • Pour les fonctions qui sont des spécialisations de modèles de fonctions, la signature inclut le type de retour.
  • Pour les fonctions qui ne sont pas des spécialisations, le type de retour ne fait pas partie de la signature.

Notez cependant que le type de retour, dans tous les cas, est une partie significative du type d'une fonction. Autrement dit, ce qui suit n'est pas valide:

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

Quand une surcharge n'est-elle pas valide si seul le type de retour diffère?

Les principaux compilateurs rejettent actuellement le code suivant:

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

Mais acceptez le code suivant:

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

Cependant, le Standard n'interdit pas une déclaration de fonction qui ne diffère que par le type de retour (lors de la définition du moment où une surcharge est valide et quand elle ne l'est pas). Il ne définit pas précisément ce que signifie "ne diffère que par le type de retour".


Références de paragraphe standard:

  • Quand peut-on surcharger une déclaration de fonction: 13.1
  • Qu'est-ce qu'une déclaration de fonction: 7/2 et 7/5
  • Quelle est la signature d'un modèle de fonction/spécialisation: 14.5.5.1

Pour référence, voici ce que dit le plus récent projet de C++ 0x n3000 sur la "signature" dans 1.3.11, qui est beaucoup plus complet dans sa couverture des différents types d'entités:

le nom et la liste des types de paramètres (8.3.5) d'une fonction, ainsi que la classe ou l'espace de noms dont elle est membre. Si une fonction ou un modèle de fonction est un membre de classe, sa signature inclut en outre les quali fi cateurs cv (le cas échéant) et le qualificatif ref (le cas échéant) sur la fonction ou le modèle de fonction lui-même. La signature d'un modèle de fonction inclut en outre son type de retour et sa liste de paramètres de modèle. La signature d'une spécialisation de modèle de fonction inclut la signature du modèle dont elle est une spécialisation et ses arguments de modèle (qu'ils soient explicitement spécifiés ou déduits). [Remarque: Les signatures sont utilisées comme base pour le changement de nom et la liaison. - note de fin]

82

Cela dépend si la fonction est un modèle de fonction ou non.

Dans Modèles C++ - les guides complets, Jusuttis fournit une définition différente de celle donnée dans la norme C++, mais avec des conséquences équivalentes:

Nous définissons la signature d'une fonction comme les informations suivantes:

  1. Le nom non qualifié de la fonction
  2. La portée de la classe ou namespace de ce nom, et si le nom a liaison interne, l'unité de traduction dans laquelle le nom est déclaré
  3. const, volatile ou const volatile qualification de la fonction
  4. Les types des paramètres de la fonction
  5. son type de retour , si la fonction est générée à partir d'un modèle de fonction
  6. Les paramètres du modèle et les arguments du modèle , si la fonction est générée à partir de un modèle de fonction

Comme litb l'a suggéré, il vaut la peine de clarifier pourquoi le type de retour fait partie de la signature d'une fonction de modèle.

Les fonctions peuvent coexister dans un programme si elles ont des signatures distinctes.

. Cela dit, si le type de retour est un paramètre de modèle:

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

il est possible d'instancier deux fonctions qui ne diffèrent que par le type de retour:

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

Non seulement: comme indiqué à juste titre par litb, il est également possible de surcharger deux fonctions de modèle, qui ne diffèrent que par le type de retour, même si le type de retour n'est pas un nom dépendant. Voici son exemple:

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'); 
10
Nicola Bonelli

Ils font suffisamment partie du type pour que vous puissiez surcharger les fonctions en fonction des types de pointeurs de fonction qui ne diffèrent que par le type de retour:

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