繁体   English   中英

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

[英]Is the return type part of the function signature?

在C ++中,返回类型是否被视为函数签名的一部分? 并且仅修改返回类型就不允许重载。

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

注意 :我已经重写了此答案,并且以下注释不适用于此修订版-有关详细信息,请参见编辑历史记录。)

介绍

但是,标准中有关函数和函数声明的问题很复杂。 必须考虑两层:

  • 声明书
  • 实体

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

标准在1.3.10定义了函数的签名,以包括以下1.3.10

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

14.5.5.1 (最近的C ++)所指出的,它缺少此定义中的返回类型,该类型函数模板特化(即声明函数的功能声明,该函数是模板的特化)的签名的一部分。 0x工作文件已修复在1.3.10中已经提到返回类型的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

作为参考,这里是最新的C ++ 0x N3000草案说,大约在“签名” 1.3.11 ,这是其在不同类型的实体的覆盖范围更加完整:

函数的名称和参数类型列表(8.3.5),以及该函数所属的类或名称空间。 如果功能或功能模板是类成员,则其签名还包括功能或功能模板本身上的cv限定符(如果有)和ref限定符(如果有)。 功能模板的签名还包括其返回类型和模板参数列表。 功能模板特化的签名包括为其特化的模板的签名及其模板自变量(无论是明确指定还是推导)。 [注意:签名用作名称处理和链接的基础。 —尾注]

这取决于功能是否为功能模板

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

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

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

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

它们是该类型的一部分,您可以根据仅返回类型不同的函数指针类型来重载函数:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM