§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);
}
答案 0 :(得分:5)
参数类型的顶级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)
- 示例]
以这种方式只忽略参数类型规范最外层的const
和volatile
类型说明符;埋在参数类型规范中的const
和volatile
类型说明符很重要,可用于区分重载的函数声明。
答案 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
}