В С++, является ли возвращаемый тип рассмотренной частью сигнатуры функции? и перегрузка не допускается с изменением типа возвращаемого типа.
Является ли часть возвращаемого типа сигнатурой функции?
Ответ 1
Нормальные функции не включают тип возврата в свою подпись.
(примечание: я переписал этот ответ, а приведенные ниже комментарии не относятся к этой ревизии - подробности см. в истории изменений).
Введение
Однако вопрос о функциях и объявлениях функций в Стандарте сложный. Необходимо учитывать два слоя:
- Объявления
- Сущности
Объявление так называемой функции может объявлять объект функции или объект шаблона. Если объявляется объект функции, то вы либо должны иметь дело с явной специализацией шаблона функции (со всеми указанными аргументами), либо с объявлением обычной функции. Если объект шаблона объявлен, тогда вы объявляете шаблон первичной функции или явную специализацию, в которой некоторые аргументы не указаны. (Это очень похоже на отношение "объявления объекта" и объектов или ссылок: первый может объявить либо объект, либо ссылку. Таким образом, объявление объекта может не обязательно объявлять объект!).
Стандарт определяет подпись функции, которая включает следующее в 1.3.10
:
Типы его параметров и, если функция является членом класса, cv-квалификаторы (если есть) для самой функции и класса, в котором объявлена функция-член. Подпись специализации шаблона включает в себя типы аргументов шаблона. (14.5.5.1)
В этом определении отсутствует тип возвращаемого значения, который является частью сигнатуры специализированной функции (т.е. объявление функции, объявляющей функцию, которая является специализацией шаблона), как указано 14.5.5.1
(недавнее С++ 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
Для справки, вот что показывает последний проект С++ 0x n3000 о "сигнатуре" в 1.3.11
, который гораздо более полно в своем охвате различных типов объектов:
имя и список типов параметров (8.3.5) функции, а также класс или пространство имен, членом которого он является. Если шаблон функции или функции является членом класса, его подпись дополнительно включает в себя cv-qualiers (если есть) и ref-quali fi (если есть) в самой функции или в шаблоне функции. Подпись шаблона функции дополнительно включает его тип возвращаемого значения и список параметров шаблона. Подпись специализированной функции шаблона включает в себя подпись шаблона, для которой она является специализацией и ее аргументами шаблона (явно или специфицировано). [Примечание. Подписи используются в качестве основы для манипулирования именами и связывания. - конечная нота]
Ответ 2
Это зависит от того, является ли функция шаблоном функции или нет.
В С++ Templates - полные руководства, Jusuttis предоставляет другое определение, данное в стандарте С++, но с эквивалентными последствиями:
Мы определяем сигнатуру функции как следующую информацию:
- Неквалифицированное имя функции
- Класс или пространство имен этого имени, и если имя имеет внутреннюю связь, единица перевода, в которой объявлено имя
- Квалификация
const
,volatile
илиconst volatile
функции - Типы параметров функции
- его тип возврата, если функция создается из шаблона функции
- Параметры шаблона и аргументы шаблона, если функция генерируется из шаблона функции
Как предлагалось 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');
Ответ 3
Они достаточно часть того типа, который вы можете перегрузить функции на основе типов указателей функций, которые отличаются только возвращаемым типом:
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)
}