79 votes

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

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

93voto

Johannes Schaub - litb Points 256113

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

( <em>note </em>: 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 niveaux à prendre en compte :

  • Déclarations
  • Entités

La soi-disant déclaration de fonction peut déclarer une entité fonction ou une entité modèle. Si une entité fonction est déclarée, alors vous devez soit faire avec 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é modèle est déclarée, alors vous déclarez un modèle de fonction primaire, 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 : Le premier peut déclarer soit un objet, soit une référence. Ainsi, un déclaration d'objet ne doit pas nécessairement déclarer 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 la 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 est 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 une spécialisation d'un modèle), comme indiqué par 14.5.5.1 (les récents documents de travail de C++0x ont déjà corrigé cela en mentionnant le type de retour dans 1.3.10 aussi) :

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

La signature d'un modèle de fonction est constituée de sa signature de fonction, de son type de retour et de sa liste de paramètres de modèle.

Que contient exactement une signature, déjà ?

Donc, lorsque nous demandons 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.

Remarquez cependant que le type de retour, dans tous les cas, est une partie importante du type d'une fonction. C'est-à-dire que ce qui suit n'est pas valable :

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

Quand une surcharge est-elle invalide 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?

Toutefois, le La norme interdit une déclaration de fonction qui ne diffère que par le type de retour. (en définissant quand une surcharge est valide et quand elle ne l'est pas). Il ne définit pas précisément ce que signifie "diffère uniquement par le type de retour".


Références de paragraphes standard :

  • Quand une déclaration de fonction peut-elle être surchargée ? 13.1
  • Qu'est-ce qu'une déclaration de fonction ? 7/2 y 7/5
  • Quelle est la signature d'une fonction modèle/spécialisation : 14.5.5.1

À titre de référence, voici ce que le projet C++0x le plus récent (n3000) dit à propos de la "signature" en 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 nom dont elle est membre. Si une fonction ou un modèle de fonction est membre d'une classe, sa signature inclut en plus les cv-qualifiers (s'il y en a) et le ref-qualifier (s'il y en a) sur la fonction ou le modèle de fonction lui-même. La signature d'un modèle de fonction inclut en plus son type de retour et sa liste de paramètres de modèle. La signature d'une spécialisation de modèle de fonction comprend 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). [ Note : Les signatures sont utilisées comme base pour le mangement de noms et la liaison. - note de fin ]

15voto

Nicola Bonelli Points 4011

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

En 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 l'information suivante :

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

Comme litb suggéré, il est utile de préciser pourquoi le type de retour fait partie de la signature d'une fonction 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 le rapporte à juste titre litb Il est également possible de surcharger deux fonctions modèles 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');

2voto

Eclipse Points 27662

Ils font suffisamment partie du type pour que vous puissiez surcharger des fonctions basées sur 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)
}

0voto

Yannis Kingdom Points 1

Je trouve qu'une façon utile d'intégrer implicitement le type de retour dans une signature est d'inclure un argument "factice" dans les entrées.

Par exemple :

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

Dans ce cas, si vous voulez une double sortie, vous entrez :

f(2, double(1))

qui renvoie le double 4.0, alors que si vous voulez une sortie int, vous entrez :

f(2, int(1))

qui renvoie l'int 4.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X