Обычные функции не включают тип возвращаемого значения в свою сигнатуру.
(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 ]
yesraaj: foo <char> будет недостаточно, поскольку есть две подходящие функции с двумя разными типами возврата. у них есть типы void (char) и int (char) после того, как компилятор поместит шаблон вместо T.
Теперь, чтобы получить правильный адрес, вам нужно дать компилятору подсказку. Ему нужен тип указателя. Это можно сделать с помощью гипса. Вы могли бы сделать (int () (char)) (foo <char>) вместо static_cast <int () (char)> (foo <char>)
но обычно лучше использовать static_cast, поскольку он сильно ограничивает область типов, к которым вы можете привести. Смотрите это stackoverflow.com/questions/103512/…
Теперь приведение типов - не единственная возможность предоставить контекст. вы также можете сделать int (* ptr) (char) = foo <char>; ptr ('Т'); и компилятор знает, что вам нужна функция-шаблон, возвращающая int. тогда вы называете это.
обратите внимание, что символ «&» в & foo <int> необязателен. Функция автоматически получит их адрес. Подобно тому, как вы называете массив, и он преобразуется в указатель на свой первый элемент.
надеюсь, это поможет вам понять эту строку кода
Я пришел сюда из этот вопрос и хотел бы знать, как сигнатура функции шаблона функции не позволяет объявлению шаблона нарушить ODR. связанный ответ предполагает, что это связано с тем, что имя модуля также включен в сигнатуру шаблона функции.
@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();
Это зависит от того, является ли функция шаблон функции или нет.
В Шаблоны C++ - полное руководство Jusuttis дает определение, отличное от того, что дано в стандарте C++, но с эквивалентными последствиями:
Мы определяем сигнатуру функции как следующую информацию:
const
, volatile
или const volatile
Как предлагает литб, стоит пояснить, почему тип возвращаемого значения является частью сигнатуры функции шаблона.
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++.
Если вы внимательно прочитаете этот пост, вы можете найти сноску во втором предложении :-)
Они хотели подчеркнуть, что шаблоны функций могут сосуществовать в одной и той же области следующим образом: template <class T> int foo (T); template <class T> bool foo (T); int main () {((int (*) (char)) foo <char>) ('а'); }
Думаю, ваш ответ пролил свет на тьму. так что я проголосовал :)
Я изменил свой ответ, чтобы отразить мою последнюю интерпретацию стандарта.
Их достаточно для того, чтобы можно было перегружать функции на основе типов указателей на функции, которые различаются только типом возвращаемого значения:
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)
}
Можете ли вы объяснить этот приведенный вызов функции static_cast <int (*) (char)> (foo <char>) ('T');