为什么标准不允许定义下面的两个函数"f"?
Why doesn't the Standard allow the definition of the two functions `f` below?
§14.8.2/4允许从模板定义实例化两个不同的函数,g<int>
和g<const int>
。为什么标准不允许定义下面代码中的两个函数f
?我知道两个函数都有相同的类型void(int)
。但是,实例化函数g
也会发生这种情况。§14.8.2/4中的注释说:f<int>(1) and f<const int>(1) call distinct functions even though both of the functions called have the same function type.
.
#include <iostream>
template<typename T>
void g(T t) { std::cout << t << 'n'; }
void f(int i) { std::cout << i << 'n'; }
//void f(int const i) { std::cout << i << 'n'; } // doesn't compile
int main()
{
g<int>(1);
g<int const>(2);
}
关于参数类型的顶级const
不属于函数签名的一部分。因此,就重载解析而言,您定义的两个版本的f()
是相同的函数,使第二个版本成为重新定义。
源自§13.1/3 [over.load]
-参数声明的区别仅在于是否存在
const
和/或volatile
。也就是说,在确定要声明、定义或调用的函数时,每个参数类型的const
和volatile
类型说明符将被忽略。(例子:typedef const int cInt; int f (int); int f (const int); // redeclaration of f(int) int f (int) { /* ... */ } // definition of f(int) int f (cInt) { /* ... */ } // error: redefinition of f(int)
-end example]
只在参数类型说明的最外层const
和volatile
类型说明符被忽略;隐藏在参数类型说明中的const
和volatile
类型说明符非常重要,可用于区分重载函数声明。
顶级const
不是函数签名的一部分,这有一个小小的优势。
假设你有一个函数"
void f(int);
在的实现中,如果你知道你不打算改变输入参数,你可以声明:
void f(int const x) {
std::cout << x << "n";
}
,这与调用者无关。稍后,更改输入值(例如,您希望将负整数视为0)会很有用:
void f(int x) {
if (x<0) x = 0;
std::cout << x << "n";
}
,而不改变签名或函数体的其余部分,我们就可以开始了。
基本上,顶级的const
参数不会影响c++中通常的二进制调用约定,并且在逻辑上,const
参数与调用者无关。通过从签名中消除这一点,我们得到了一些好处。
对于template
函数,类型既影响签名,也影响函数体,而函数体是template
接口的一部分。(decltype
允许函数参数的类型影响函数体,但函数体不像template
那样是接口的一部分)
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 两个函数模板候选项.将一个参数作为引用后,选择不太专业的模板
- 如何比较两个函数的速度和性能
- 如何在构造器的成员初始值设定项列表中调用两个函数?
- 如何将这两个函数组合成一个实现?
- 将具有相反操作数的两个函数重构为一个
- 创建整数的 2D 数组,该数组将使用两个函数用随机数填充矩阵.我做错了什么?
- 具有相同主体的两个函数具有不同的名称
- 通过作为类的公共成员的两个函数将函数作为参数传递
- 如何使用排序和比较这两个函数在 c++ 中对字符数组进行排序?
- 是否可以在C++中将两个函数一起添加
- C++ 两个函数除了一行之外执行相同的操作
- 如何编写连接两个函数的函数
- 如何执行两个函数参数具有相同的模板类型
- 当两个函数位于一行中时,堆栈框架的样子
- 为什么这两个函数的行为不同
- 为什么当我有两个函数时编译器没有显示错误,一个将采用基类,一个将派生类作为参数
- 系统堆栈中的两个函数的递归调用(将不同数量的数组作为参数传递)有什么区别
- 如何在一个构造函数中使用两个可变参数模板参数来绑定两个函数
- 如何在c++中的两个函数中传递对象的同一实例