返回类型是函数签名的一部分吗?

时间:2008-11-14 13:17:16

标签: c++ function

在C ++中,返回类型是否被认为是函数签名的一部分?只修改了返回类型,不允许重载。

3 个答案:

答案 0 :(得分:81)

普通函数的签名中不包含返回类型。

note :我已经重写了这个答案,以下评论不适用于此修订版 - 有关详细信息,请参阅编辑历史记录。)

简介

然而,标准中关于函数和函数声明的问题很复杂。必须考虑两个层次:

  • 声明
  • 实体

所谓的函数声明可以声明一个函数实体或一个模板实体。如果声明了一个函数实体,那么您要么必须使用函数模板的显式特化(指定所有参数),要么使用普通函数的声明。如果声明了模板实体,那么您将声明主函数模板,或者未指定某些参数的显式特化。 (这与“对象声明”和对象或引用的关系非常相似:前者可以声明对象或引用。因此对象声明可能不一定声明对象!)。

标准定义了一个函数的签名,以便在1.3.10包含以下内容:

  

其参数的类型,如果函数是类成员,则函数本身的cv限定符(如果有)以及声明成员函数的类。函数模板特化的签名包括其模板参数的类型。 (14.5.5.1)

它缺少此定义中的返回类型,其中函数模板特化的签名的一部分(即声明函数是模板特化的函数声明),如指向的那样out 14.5.5.1(最近的C ++ 0x工作文件修正了已经提到1.3.10中的返回类型):

  

函数模板特化的签名包括函数模板的签名和实际模板参数的签名(无论是明确指定还是推导)。

     

函数模板的签名包括其函数签名,返回类型和模板参数列表。

那么签名究竟包含什么呢?

因此,当我们询问函数的签名时,我们必须给出两个答案:

  • 对于作为功能模板特化的函数,签名包括返回类型。
  • 对于非特化的函数,返回类型不是签名的一部分。

但请注意,返回类型(无论如何) 是函数类型的重要部分。也就是说,以下内容无效:

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/27/5
  • 功能模板/专业化的签名是什么:14.5.5.1

作为参考,以下是1.3.11中最新的C ++ 0x草案n3000关于“签名”的内容,它对不同类型实体的覆盖范围要完整得多:

  

函数的名称和参数类型列表(8.3.5),以及它所属的类或命名空间。如果函数或函数模板是类成员,则其签名还包括函数或函数模板本身的cv-quali firs(如果有)和ref-quali fi er(如果有)。函数模板的签名还包括其返回类型和模板参数列表。函数模板特化的签名包括作为特化的模板的签名及其模板参数(无论是明确指定还是推导)。 [注意:签名用作名称修改和链接的基础。 - 结束说明]

答案 1 :(得分:10)

这取决于函数是否是函数模板

C ++模板 - 完整指南中,Jusuttis提供了与C ++标准中给出的不同的定义,但具有相同的结果:

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

  1. 函数的非限定名称
  2. 该名称的名称空间范围,如果名称具有内部链接,则声明名称的翻译单位
  3. 该功能的constvolatileconst volatile限定
  4. 功能参数的类型
  5. 返回类型,如果函数是从函数模板生成的
  6. 模板参数模板参数,如果函数是从函数模板生成的
  7. 正如 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'); 
    

答案 2 :(得分:2)

它们足以成为类型的一部分,您可以根据仅由返回类型不同的函数指针类型重载函数:

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