Является ли возвращаемый тип частью сигнатуры функции? - PullRequest
65 голосов
/ 14 ноября 2008

В C ++ считается ли тип возвращаемого значения частью сигнатуры функции? и не допускается перегрузка только с измененным типом возврата.

Ответы [ 3 ]

81 голосов
/ 14 ноября 2008

Обычные функции не включают тип возвращаемого значения в свою подпись.

( примечание : я переписал этот ответ, и приведенные ниже комментарии не относятся к этой ревизии - подробности см. В истории изменений).

Введение

Однако вопрос о функциях и объявлениях функций в Стандарте сложен. Есть два слоя, которые необходимо учитывать:

  • Объявления
  • Объекты

Так называемое объявление функции может объявлять объект функции или объект шаблона. Если объект функции объявлен, то вы должны либо иметь явную специализацию шаблона функции (с указанием всех аргументов), либо объявление обычной функции. Если объект шаблона объявлен, то вы объявляете шаблон первичной функции или явную специализацию, в которой некоторые аргументы не указаны. (Это очень похоже на отношение «объявления объекта» и объектов или ссылок: первое может объявлять либо объект, либо ссылку. Поэтому объявление объекта не обязательно может объявлять объект!).

Стандарт определяет сигнатуру функции для включения следующего в 1.3.10:

Типы ее параметров и, если функция является членом класса, cv-квалификаторы (если таковые имеются) для самой функции и класса, в котором объявлена ​​функция-член. Подпись специализации шаблона функции включает типы аргументов шаблона. (14.5.5.1)

В этом определении отсутствует возвращаемый тип, который является частью сигнатуры специализации шаблона функции (т.е. объявления функции, которая объявляет функцию, которая является специализацией шаблона), как указано 14.5.5.1 (исправлены последние рабочие документы C ++ 0x, в которых уже упоминался тип возврата в 1.3.10):

Подпись специализации шаблона функции состоит из подписи шаблона функции и фактических аргументов шаблона (явно указанных или выведенных).

Сигнатура шаблона функции состоит из сигнатуры его функции, типа возвращаемого значения и списка параметров шаблона.

Итак, что же конкретно содержит подпись?

Итак, когда мы спрашиваем о сигнатуре функции , мы должны дать два ответа:

  • Для функций, которые являются специализациями шаблонов функций, подпись включает тип возвращаемого значения.
  • Для функций, которые не являются специализациями, тип возвращаемого значения не является частью сигнатуры.

Однако обратите внимание, что тип возвращаемого значения в любом случае составляет значительную часть типа функции. То есть следующее недопустимо:

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

Когда недопустима перегрузка, если отличается только тип возвращаемого значения?

Основные компиляторы в настоящее время отклоняют следующий код:

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

Но примите следующий код:

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

Однако стандарт запрещает объявление функции, которая отличается только типом возвращаемого значения (при определении, когда перегрузка допустима, а когда нет). Однако он точно не определяет, что означает «отличается только типом возврата».


Стандартные ссылки на абзацы:

  • Когда может быть перегружено объявление функции: 13.1
  • Что такое объявление функции: 7/2 и 7/5
  • Что такое подпись шаблона функции / специализации: 14.5.5.1

Для справки, вот что говорит самый последний черновик C ++ 0x n3000 о «подписи» в 1.3.11, что гораздо более полно в охвате различных типов сущностей:

имя и список типов параметров (8.3.5) функции, а также класс или пространство имен, членом которого она является. Если функция или шаблон функции является членом класса, его сигнатура дополнительно включает в себя cv-квалификаторы (если есть) и ref-квалификатор (если есть) для самой функции или самого шаблона функции. Сигнатура шаблона функции дополнительно включает тип возвращаемого значения и список параметров шаблона. Сигнатура специализации шаблона функции включает в себя сигнатуру шаблона, специализацией которого она является, и аргументы шаблона (явно ли они указаны или выведены). [Примечание: подписи используются в качестве основы для искажения имени и связывания. - конец примечания]

10 голосов
/ 15 ноября 2008

Зависит от того, является ли функция шаблоном функции или нет.

В C ++ Templates - полные руководства , Jusuttis предоставляет другое определение, которое дано в стандарте C ++, но с эквивалентными последствиями:

Мы определяем сигнатуру функции как следующую информацию:

  1. безусловное имя функции
  2. Область имен class или область действия этого имени, а если имя имеет внутреннюю связь, модуль перевода, в котором объявлено имя
  3. Квалификация функции const, volatile или const volatile
  4. Типы параметров функции
  5. его возвращение тип , если функция генерируется из шаблона функции
  6. Параметры шаблона и аргументы шаблона , если функция генерируется из шаблона функции

Как и предполагалось litb , стоит пояснить, почему возвращаемый тип является частью сигнатуры функции шаблона.

Функции могут сосуществовать в программе, если у них разные подписи.

. Тем не менее, если тип возвращаемого значения является параметром шаблона:

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

можно создать две функции, которые отличаются только типом возвращаемого значения:

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

Не только: как справедливо сообщается в litb , также возможно перегрузить две функции шаблона, которые отличаются только типом возвращаемого значения, даже если тип возвращаемого значения не является зависимым именем. Вот его пример:

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'); 
2 голосов
/ 21 ноября 2008

Они достаточно часть типа, чтобы можно было перегружать функции на основе типов указателей на функции, которые отличаются только типом возвращаемого значения:

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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...