函数签名是返回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/27/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 ++标准中给出的不同定义,但是具有相同的结果:

我们将函数的签名定义为以下信息:

  1. 函数的非限定名称
  2. 名称名称空间范围,如果名称具有内部链接,则声明该名称的翻译单元
  3. constvolatileconst volatile限定
  4. 函数参数的types
  5. 它的返回types ,如果函数是从函数模板生成的
  6. 模板参数模板参数 (如果函数是从函数模板生成的)

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