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

时间:2014-07-15 18:01:55

标签: c++ templates c++11

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

2 个答案:

答案 0 :(得分:5)

参数类型的顶级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)
     

- 示例]
  以这种方式只忽略参数类型规范最外层的constvolatile类型说明符;埋在参数类型规范中的constvolatile类型说明符很重要,可用于区分重载的函数声明。

答案 1 :(得分:0)

顶级const不属于函数签名的事实允许一个小优势。

假设你有一个功能&#34;

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}

的界面的一部分