为什么标准不允许定义下面的两个函数"f"?

Why doesn't the Standard allow the definition of the two functions `f` below?

本文关键字:两个 函数 不允许 标准 定义 为什么      更新时间:2023-10-16

§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。也就是说,在确定要声明、定义或调用的函数时,每个参数类型的constvolatile类型说明符将被忽略。(例子:

 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]
只在参数类型说明的最外层constvolatile类型说明符被忽略;隐藏在参数类型说明中的constvolatile类型说明符非常重要,可用于区分重载函数声明。

顶级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那样是接口的一部分)