我正在研究 c++ 模板,并编写如下所示的示例:
#include <vector>
#include <iostream>
#include <type_traits>
#include <typeinfo>
using namespace std;
template <typename T>
void fcn(T &&val)
{
cout << is_same<T, int&>::value << endl;
const T t = val;
//T const t = val;
cout << typeid(t).name() << endl;
t = 10;
cout << "val: " << val;
cout << ", t: " << t << endl;
return;
}
int main()
{
cout << boolalpha;
int i{};
fcn(i);
}
我希望这段代码无法成功编译,但没有错误,输出:
true
i
val: 10, t: 10
我有两个问题:
gcc推导出T是
int& type
,const T t = val
行,表示t常量绑定到val,像这样:const int &t = val
,为什么常量没有效果? t 和 i 值可以改变吗?我用
typeid(t).name()
来显示t的类型,为什么只打印i
?
- 在你的情况下,
const T
T = int&
手段,给我一个我无法重新分配的参考。但是引用永远不可分配,它总是指向同一个对象。所以它坍缩到T
,在这种情况下是int&
。
要使其按预期工作,请使用std::remove_reference
请参阅: C++ 模板中的常量引用
name
返回实现定义的内容,因此没有太多可说的。
- gcc 推断
T
是int&
类型,const T t = val
表示 t 常量绑定到 val,为什么const
没有效果?
此函数模板签名
template <typename T> void fcn(T &&val);
使用转发引用。简而言之,当用左值int
推导实例化时(您的情况),您最终会得到T = int&
,即包括引用。引用折叠将void fcn(T& &&val)
转换为void fcn(T& val)
。
当你声明const T t
时,这意味着T& const
(const
修改它左边的东西,如果它左边什么都没有,它修改它右边的东西)。但这无效,因为没有const
限定引用这样的东西,因此删除了const
限定符。
- 我用
typeid(t).name()
来显示t的类型,为什么只打印i
?
typeid(t).name()
不需要输出人类可读的标识符。i
代表int
,因此根据编译器的不同,这是您应该期望的。当使用clang
或gcc
时,通过显示类型通常更好
template <class T> p(T&&) { std::cout << __PRETTY_FUNCTION__; }
p(t); // prints out understandable type info
我编写了另一个程序来研究使用"类型别名"const T
:
#include <iostream>
using namespace std;
int main()
{
int i {};
using T = int *;
const T t = &i; // same with T const t = &i;
*t = 10;
cout << i << endl;
int j{};
//t = &j; // error, t is int * const
}
编译成功,输出:10
.
现在我可以理解为什么编译器认为const T
是int * const
,而不是const int *
,因为编译器将T
视为像int
,char
,而不是int *
一样的常见类型,它不是替换。