函数签名是返回types的一部分吗?
在C ++中,返回types是否被认为是函数签名的一部分? 只要修改了返回types就不允许重载。
普通函数在签名中不包括返回types。
( 注意 :我已经重写了这个答案,下面的评论不适用于这个修订版本 – 请参阅编辑历史了解详情)。
介绍
但是,标准中有关函数和函数声明的事情是复杂的。 有两层需要考虑:
- 声明
- 实体
所谓的函数声明可以声明一个函数实体或一个模板实体。 如果一个函数实体被声明了,那么你必须做一个显式的特化函数模板(指定所有参数)或者一个普通函数的声明。 如果一个模板实体被声明,那么你声明了一个主函数模板,或者一个明确的专门化,其中没有指定一些参数。 (这与“对象声明”和对象或引用的关系非常相似:前者可以声明对象或引用,因此对象声明可能不一定声明对象!)。
标准定义了一个函数的签名,在1.3.10
包含以下1.3.10
:
其参数的types,如果函数是类成员,则函数本身的cv-限定符(如果有)以及声明成员函数的类。 函数模板特化的签名包括模板参数的types。 (14.5.5.1)
它缺less这个定义中的返回types,这是函数模板特化(即声明一个模板专用函数的函数声明)的一部分,正如14.5.5.1
(最近的C ++修正了在1.3.10
中已经提到返回types的0x工作底稿):
函数模板专门化的签名由函数模板的签名和实际的模板参数(无论是明确指定还是推导)组成。
函数模板的签名由函数签名,返回types和模板参数列表组成。
那么签名又包含了什么呢?
所以,当我们询问一个函数的签名时,我们必须给出两个答案:
- 对于函数模板的特化函数,签名包括返回types。
- 对于不是专门化的函数,返回types不是签名的一部分。
但是请注意,返回types在任何情况下都是函数types的重要组成部分。 也就是说,以下是无效的:
void f(); int (*pf)() = &f; // different types!
如果只有返回types不同,何时重载无效?
主要的编译器目前拒绝下面的代码:
int f(); double f(); // invalid
但接受下面的代码:
template<typename T> int f(); template<typename T> double f(); // invalid?
但是, 标准禁止函数声明只在返回types中有所不同 (当定义何时超载有效,何时不)。 但是,它并没有精确地定义“只有返回types才有差别”的含义。
标准段落参考:
- 什么时候可以重载函数声明:
13.1
- 什么是函数声明:
7/2
和7/5
- 函数模板/特化的签名是什么:
14.5.5.1
作为参考,这里是最新的C ++ 0x草案n3000在1.3.11中对“签名”所说的内容,它在覆盖不同types的实体方面更为完整:
函数的名称和参数types列表(8.3.5),以及它所属的类或名称空间。 如果函数或函数模板是类成员,则其签名还包括函数或函数模板本身上的cv限定符(如果有)和ref-quali fi er(如果有)。 函数模板的签名额外包括其返回types及其模板参数列表。 函数模板专门化的签名包括专门化模板的签名和它的模板参数(无论是明确指定的还是推导的)。 [注:签名被用作名称修改和链接的基础。 – 结束注意]
这取决于函数是否是函数模板 。
在C ++模板 – 完整的指南中 ,Jusuttis提供了C ++标准中给出的不同定义,但是具有相同的结果:
我们将函数的签名定义为以下信息:
- 函数的非限定名称
- 该名称的类或名称空间范围,如果名称具有内部链接,则声明该名称的翻译单元
-
const
,volatile
或const volatile
限定 - 函数参数的types
- 它的返回types ,如果函数是从函数模板生成的
- 模板参数和模板参数 (如果函数是从函数模板生成的)
正如litb所build议的,值得澄清为什么返回types是模板函数签名的一部分。
如果函数具有不同的签名,函数可以共存于一个程序中。
。 也就是说,如果返回types是一个模板参数:
template <typename T> T foo(int a) {return T();}
实例化仅在返回types中不同的两个函数是可能的:
foo<int>(0); foo<char>(0);
不仅如此 ,正如litb所报道的,即使返回types不是依赖名称,也可以重载两个仅在返回types中不同的模板函数。 这是他的例子:
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');
它们足以成为types的一部分,您可以根据函数指针types来重载函数,而函数指针types的区别仅在于返回types:
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) }