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

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

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
70
0
45 786
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

(note: i've rewritten this answer, and the comments below don't apply to this revision - see the edit-history for details).

Введение

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

  • Декларации
  • Сущности

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

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

The types of its parameters and, if the function is a class member, the cv- qualifiers (if any) on the function itself and the class in which the member function is declared. The signature of a function template specialization includes the types of its template arguments. (14.5.5.1)

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

The signature of a function template specialization consists of the signature of the function template and of the actual template arguments (whether explicitly specified or deduced).

The signature of a function template consists of its function signature, its return type and its template parameter list.

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

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

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

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

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

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

the name and the parameter type list (8.3.5) of a function, as well as the class or namespace of which it is a member. If a function or function template is a class member its signature additionally includes the cv-qualifiers (if any) and the ref-qualifier (if any) on the function or function template itself. The signature of a function template additionally includes its return type and its template parameter list. The signature of a function template specialization includes the signature of the template of which it is a specialization and its template arguments (whether explicitly specified or deduced). [ Note: Signatures are used as a basis for name mangling and linking. — end note ]

Можете ли вы объяснить этот приведенный вызов функции static_cast <int (*) (char)> (foo <char>) ('T');

yesraaj 18.11.2008 10:04

yesraaj: foo <char> будет недостаточно, поскольку есть две подходящие функции с двумя разными типами возврата. у них есть типы void (char) и int (char) после того, как компилятор поместит шаблон вместо T.

Johannes Schaub - litb 18.11.2008 14:31

Теперь, чтобы получить правильный адрес, вам нужно дать компилятору подсказку. Ему нужен тип указателя. Это можно сделать с помощью гипса. Вы могли бы сделать (int () (char)) (foo <char>) вместо static_cast <int () (char)> (foo <char>)

Johannes Schaub - litb 18.11.2008 14:37

но обычно лучше использовать static_cast, поскольку он сильно ограничивает область типов, к которым вы можете привести. Смотрите это stackoverflow.com/questions/103512/…

Johannes Schaub - litb 18.11.2008 14:40

Теперь приведение типов - не единственная возможность предоставить контекст. вы также можете сделать int (* ptr) (char) = foo <char>; ptr ('Т'); и компилятор знает, что вам нужна функция-шаблон, возвращающая int. тогда вы называете это.

Johannes Schaub - litb 18.11.2008 14:43

обратите внимание, что символ «&» в & foo <int> необязателен. Функция автоматически получит их адрес. Подобно тому, как вы называете массив, и он преобразуется в указатель на свой первый элемент.

Johannes Schaub - litb 18.11.2008 14:46

надеюсь, это поможет вам понять эту строку кода

Johannes Schaub - litb 18.11.2008 14:46

Я пришел сюда из этот вопрос и хотел бы знать, как сигнатура функции шаблона функции не позволяет объявлению шаблона нарушить ODR. связанный ответ предполагает, что это связано с тем, что имя модуля также включен в сигнатуру шаблона функции.

nonsensickle 20.10.2015 07:08
Продолжение: Итак, я спрашиваю, можете ли вы добавить к своему ответу раздел, в котором объясняется, играет ли имя модуля роль в подписи шаблона функции?
nonsensickle 20.10.2015 07:09

@nonsensickle A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated. Теперь создание экземпляра создаст неоднозначный вызов, потому что это конкретное определение шаблонов не различает их, хотя вы можете использовать SFINAE, например template<typename T> typename std::enable_if<std::is_integral<T>::value,int>::type f();

Swift - Friday Pie 29.04.2019 09:52

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

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

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

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

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

Functions can coexist in a program if they have distinct signatures.

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

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

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

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

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

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

В сноске говорится: «Это определение отличается от того, что дано в стандарте C++, но его последствия эквивалентны». Таким образом, это определение некоторой книги, но не C++.

Johannes Schaub - litb 15.11.2008 14:37

Если вы внимательно прочитаете этот пост, вы можете найти сноску во втором предложении :-)

Nicola Bonelli 15.11.2008 14:40

Они хотели подчеркнуть, что шаблоны функций могут сосуществовать в одной и той же области следующим образом: template <class T> int foo (T); template <class T> bool foo (T); int main () {((int (*) (char)) foo <char>) ('а'); }

Johannes Schaub - litb 15.11.2008 14:42

Думаю, ваш ответ пролил свет на тьму. так что я проголосовал :)

Johannes Schaub - litb 15.11.2008 15:11

Я изменил свой ответ, чтобы отразить мою последнюю интерпретацию стандарта.

Johannes Schaub - litb 18.12.2009 15:03

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

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

Другие вопросы по теме