首页 > 编程语言 >小议C++函数签名与模板返回类型

小议C++函数签名与模板返回类型

时间:2023-06-15 15:01:35浏览次数:45  
标签:return 函数 get int double C++ 编译器 签名 模板


题记:什么事情都要追问一个为什么,真正理解了为什么,才能活学活用。

代码1

下面的代码能编译通过吗?

#include <stdio.h>
#include <stdlib.h>

class X
{
public:
    int *get() { return new int(); }
    double *get() { return new double(); }
};

int main()
{
    int * v1 = X().get();
    double * v2 = X().get();
    return 0;
}

答案肯定是编译不过。因为下面两个函数的“签名”是一样的:

int *get();
    double *get();

在 C++ 语言中,函数签名包含函数名称、函数参数类型、函数参数个数等信息,但是不包含返回值类型。

代码2

下面的代码能编译通过吗?

#include <stdio.h>
#include <stdlib.h>

class X
{
public:
  template <class T>
  T *get() { return new T(); }
};

int main()
{
  int * v1 = X().get<int>();
  double * v2 = X().get<double>();
  return 0;
}

答案是可以编译通过!这是为什么呢????难道 X 这个模板对象展开后,不是展开成类似下面的样子吗:

class X
{
public:
    int *get() { return new int(); }
    double *get() { return new double(); }
};

按照 代码1 的分析和结论,这样是编译不过的才对呀!

解惑

C++ 标准里是明确定义了,函数签名不包含返回值类型。但是,为什么要这样定义呢?原因如下:

虽然,下面的调用理论上编译器是可以帮忙选出正确函数:

int * v1 = X().get();
    double * v2 = X().get();

但是,下面的场景编译器就会犯糊涂:

X().get();

不使用返回值的调用方式 C++ 是允许的,但是这种情况下,编译器应该为它链接哪一个函数呢?编译器也不知道!正是因为存在这种不好解析的场景存在,C++才把“返回值类型”从函数签名中剔除。

明白了这个道理,就不难理解 ** 代码2 ** 为何可以编译通过了。下面的调用不存在任何二义性,所以编译器才允许模板函数中使用模板参数定义返回值类型。

X().get<int>();
    X().get<double>();

使用 nm 工具可以看到,编译之后类型信息也加入到符号中了:

小议C++函数签名与模板返回类型_开发语言


小议C++函数签名与模板返回类型_开发语言_02

你学废了吗?

补充资料

并不是所有语言都不允许返回值类型作为函数签名的。比如 Swift 语言。那么它是如何解决二义性问题的呢?很简单,针对 X().get() 这种调用直接报错!除非提供足够信息帮助编译器正确推导出完整签名。

func some() -> Bool {
    return true;
}

func some() -> Int {
    return 1;
}

// 编译成功,编译器可以找到正确的函数
let valBool: Bool = some()
let valInt: Int = some()

// 编译失败,编译器无法确定应该使用哪个函数
some()

参考资料:Stack Overflow: Why is the return type of method not included in the method-signature?


标签:return,函数,get,int,double,C++,编译器,签名,模板
From: https://blog.51cto.com/u_16162111/6492557

相关文章

  • 【代码仓库】【模板】树链剖分
    #include<bits/stdc++.h>#definerep(i,a,b)for(inti=(a);i<=(b);i++)#definepre(i,a,b)for(inti=(a);i>=(b);i--)#defineEde(i,u)for(inti=h[u];i;i=ne[i])#definego(i,a)for(autoi:a)//#defineintlonglong#def......
  • 云小课|RDS for MySQL参数模板一键导入导出,参数配置轻松搞定
    摘要:云数据库RDSforMySQL支持参数模板的导入和导出功能。本文分享自华为云社区《【云小课】【第56课】RDSforMySQL参数模板一键导入导出,参数配置轻松搞定》,作者:数据库的小云妹。云数据库RDSforMySQL支持参数模板的导入和导出功能。导入参数模板:导入后会生成一个新的参数模板,......
  • 云小课|RDS for MySQL参数模板一键导入导出,参数配置轻松搞定
    摘要:云数据库RDSforMySQL支持参数模板的导入和导出功能。本文分享自华为云社区《【云小课】【第56课】RDSforMySQL参数模板一键导入导出,参数配置轻松搞定》,作者:数据库的小云妹。云数据库RDSforMySQL支持参数模板的导入和导出功能。导入参数模板:导入后会生成一个新的参......
  • C++模板
    1.名词概念模板类,模板函数,特化模板(templatespecialization)2.注意事项模板必须在头文件中实现,以下情况除外:如果只在cpp内用到的模板函数,是可以在cpp中实现的,参见oceanbase/updateserver中的response_data_函数;还有特化的模板函数,也可以在cpp中实现,参见oceanbase/updateserver中的......
  • C++类中static不计算入sizeof
    classMyParam{public:inta;staticintb;intc;staticinty;staticintz;};sizeof(MyParam)=8intMyParam::b=10;intMyParam::z=10;intmain(){MyParamp;MyParamdest;p.a=10;p.b=2;p.c=4;memcpy(&am......
  • C++构造函数复习
    #include<iostream>usingnamespacestd;classElement{public:Element(inte=12):elem(e){cout<<"element1"<<endl;}intelem;};classArrayHelper{public:ArrayHelper(){......
  • 如何寻找 C++ 程序中的大对象?
    问题背景大型应用程序中包含成千上万个C++对象,这些对象大小如何?有没有一些大对象很废?例如,在OceanBase0.4开源版本中Top10的大对象,最大的一个占58MB内存:排序大小类名158,720,304rootserver::ObRootTable2220,163,008updateserver::ObUpdateServerMain320,15......
  • C++ 文件和流
     到目前为止,我们已经使用了 iostream 标准库,它提供了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流。本教程介绍如何从文件读取流和向文件写入流。这就需要用到C++中另一个标准库 fstream,它定义了三个新的数据类型:数据类型描述ofstream该数据类......
  • C/C++商品信息管理系统[2023-06-15]
    C/C++商品信息管理系统[2023-06-15]选题4商品信息管理系统的设计与实现设计要求本课题要求同学们完成一个信息管理类的课题---《商品信息管理系统》,能够对商品信息进行有效的管理,实现商品信息查询、商品销售、商品进货、商品销售信息统计等方面的基本操作。管理内容(商品信息......
  • Luogu P1495 【模板】中国剩余定理(CRT)/ 曹冲养猪
    【模板】中国剩余定理(CRT)/曹冲养猪题目描述自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。举个例子,假如有\(16\)头母猪,如果建了\(3\)个猪圈,剩下......