Является ли возвращаемый тип частью сигнатуры функции?


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

3 61

3 ответа:

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

(Примечание: я переписал этот ответ, и комментарии ниже не относятся к этой ревизии - см. историю редактирования для получения подробной информации).

введение

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

  • декларации
  • объекты

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

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

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

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

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

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

Ну и что точно ли подпись содержит, опять же?

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

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

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

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-квалификатор (если таковые имеются) на самой функции или шаблоне функции. Подпись шаблона функции дополнительно включает его возвращаемый тип и его список параметров шаблона. Сигнатура специализации шаблона функции включает в себя сигнатуру шаблона, для которого он является специализацией, и его аргументы шаблона (явно заданные или выведенные). [Примечание: подписи используются в качестве основы для искажения имен и связывания. - конец Примечание ]

это зависит, если функция является шаблон функции или нет.

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

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

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

как 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'); 

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

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