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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/290038/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:22:50  来源:igfitidea点击:

Is the return type part of the function signature?

c++function

提问by yesraaj

In C++, is the return type considered part of the function signature? and no overloading is allowed with just return type modified.

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

回答by Johannes Schaub - litb

Normal functions do not include the return type in their signature.

普通函数在其签名中不包括返回类型。

(note: i've rewritten this answer, and the comments below don't apply to this revision - see the edit-history for details).

注意:我已经重写了这个答案,下面的评论不适用于这次修订——详情请参见编辑历史)。

Introduction

介绍

However, the matter about functions and function declarations in the Standard is complicated. There are two layers that have to be considered:

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

  • Declarations
  • Entities
  • 声明
  • 实体

The so-called function declarationmay declare a function entity or a template entity. If a function entity is declared, then you either have to do with an explicit specialization of a function template (with all arguments specified), or a declaration of an ordinary function. If a template entity is declared, then you are declaring a primary function template, or an explicit specialization where some arguments are not specified. (This is very similar to the relation of "object declaration" and objects or references: The former may declare either an object or a reference. So an object declarationmay not necessarily declare an object!).

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

The Standard defines the signature of a function to include the following at 1.3.10:

该标准定义了一个函数的签名,包括以下内容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)

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

It's missing the return type in this definition, which ispart of the signature of a function template specialization (i.e a function declaration that declares a function which is a specialization of a template), as pointed out by 14.5.5.1(recent C++0x working papers fixed that already to mention the return type in 1.3.10too):

它缺少此定义中的返回类型,它函数模板特化签名的一部分(即声明函数的函数声明是模板的特化),正如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.

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

函数模板的签名由函数签名、返回类型和模板参数列表组成。

So what exactly does a signature contain, again?

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

So, when we ask about the signature of a function, we have to give two answers:

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

  • For functions that are specializations of function templates, the signature includes the return type.
  • For functions that are not specializations, the return type is not part of the signature.
  • 对于函数模板的特化函数,签名包括返回类型。
  • 对于非特化函数,返回类型不是签名的一部分。

Notice, however, that the return type, in any case, isa significant part of the type of a function. That is, the following is not valid:

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

void f();
int (*pf)() = &f; // different types!

When is an overload invalid if only the return type differs?

如果只有返回类型不同,重载何时无效?

Major compilers currently reject the following code:

主要编译器目前拒绝以下代码:

int f();
double f(); // invalid

But accept the following code:

但接受以下代码:

template<typename T> int f();
template<typename T> double f(); // invalid?

However, the Standard does forbid a function declaration that only differs in the return type(when defining when an overload is valid, and when not). It does not define precisely what "differs only by return type" means, though.

但是,标准确实禁止仅在返回类型上不同的函数声明(定义重载何时有效,何时无效)。不过,它并没有准确定义“仅因返回类型不同”的含义。



Standard paragraph references:

标准段落参考:

  • When can a function declaration be overloaded: 13.1
  • What is a function declaration: 7/2and 7/5
  • What is the signature of a function template/specialization: 14.5.5.1
  • 什么时候可以重载函数声明: 13.1
  • 什么是函数声明:7/27/5
  • 函数模板/特化的签名是什么: 14.5.5.1

For reference, here is what the most recent C++0x draft n3000 says about "signature" in 1.3.11, which is much more complete in its coverage of the different type of entities:

作为参考,以下是最新的 C++0x 草案 n3000 关于 中的“签名”的说法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-quali?ers (if any) and the ref-quali?er (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 speci?ed or deduced). [ Note: Signatures are used as a basis for name mangling and linking. — end note ]

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

回答by Nicola Bonelli

It depends if the function is a function templateor not.

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

In C++ Templates -- the complete guides, Jusuttis provides a different definition of that given in the C++ standard, but with equivalent consequences:

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

We define the signature of a function as the the following information:

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

  1. The unqualified nameof the function
  2. The classor namespacescope of that name, and if the name has internal linkage, the translation unit in which the name is declared
  3. The const, volatile, or const volatilequalification of the function
  4. The typesof the function parameters
  5. its return type, if the function is generated from a function template
  6. The template parametersand the template arguments, if the function is generated from a function template
  1. 函数的非限定名称
  2. 名称命名空间范围,如果该名称具有内部链接,则在其中声明该名称的翻译单元
  3. constvolatileconst volatile功能的资格
  4. 函数参数的类型
  5. 它的返回类型,如果函数是从函数模板生成的
  6. 模板的参数模板参数,如果函数是从一个函数模板生成

As litbsuggested, it's worth to clarify why the return type is part of the signature of a template function.

正如litb 所建议的,有必要澄清为什么返回类型是模板函数签名的一部分。

Functions can coexist in a program if they have distinct signatures.

如果函数具有不同的签名,则它们可以在程序中共存。

. That said, if the return type is a template parameter:

. 也就是说,如果返回类型是模板参数:

template <typename T>
T foo(int a)
{return T();}

it's possibile to instantiate two function which differ only in the return type:

可以实例化两个仅在返回类型上不同的函数:

foo<int>(0);
foo<char>(0);

Not only: as rightly reported by litb, it is also possible to overload two template functions, which differ only in the return type, even if the return type is not a dependent name. Here's his example:

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

回答by Eclipse

They are enough a part of the type that you can overload functions based on function pointer types that differ only by return type:

它们足以作为类型的一部分,您可以基于仅因返回类型而不同的函数指针类型重载函数:

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