使用引用作为模板类型
Using reference as template type
在下面的示例中,Foo
没有做预期的事情,但我无法弄清楚为什么允许编译它。
#include <string>
#include <iostream>
typedef std::string& T;
T Foo(int & i)
{
return T(i);
}
int main()
{
int a = 1;
std::string & s = Foo(a);
}
我在模板中发现了这一点,但typedef
显示它与模板无关。 不用说,s
在这里不是一个有效的字符串。 我认为在返回Foo
时构造值会产生编译错误。
我在这里错过了什么?
首先,这个问题实际上与模板无关,这是毫无价值的,因为这段代码编译得很好:
typedef std::string& T;
T Foo(int& i) {
return T(i);
}
我认为这编译的原因是return
语句等效
return reinterpret_cast<T>(i);
万一T
碰巧是参考成员。当然,这编译:你答应你知道你在做什么,并要求编译器相信你。
好的,在 5.2.3 [expr.type.conv] 第 1 段中找到它:
。如果表达式列表是单个表达式,则类型转换表达式等效(在定义性上,如果在含义上定义)与相应的强制转换表达式 (5.4) 等效。...
。以及 5.4 [Expr.cast] 第 4 段:
由 [其他形式的强制转换] reinterpret_cast (5.2.10) [...] 执行的转换可以使用显式类型转换的强制转换表示法来执行。[...]
(省略涵盖涉及用户定义类型、内置类型转换const
转换等的情况)
这与模板无关,如果T
只是std::string&
的typedef而不是推导的模板参数,你会得到相同的结果:
#include <string>
typedef std::string& T;
T Foo(int & i)
{
return T(i);
}
int main()
{
int a = 1;
std::string & s = Foo(a);
}
Dietmar的回答让我意识到这可以进一步简化为:
#include <string>
typedef std::string& T;
int main()
{
int a = 1;
std::string & s = T(a);
}
其中T(a)
与铸件相同(T)a
即(std::string&)a
(根据 5.4 [expr.castconst_cast
] 的规则)如果有效(它不是)或一个static_cast
,如果有效(它不是),或者一个static_cast
后跟一个const_cast
,如果它是有效的(它不是),或者一个reinterpret_cast
,如果它是有效的(它是),或者一个reinterpret_cast
后跟一个const_cast
,如果这是有效的, 否则表达式格式不正确。
所以正如迪特马尔所说,这和做一个reinterpret_cast
是一样的,即
std::string & s = reinterpret_cast<std::string&>(a);
我觉得原始代码编译很令人惊讶,但由于它与上面的那行相同,因此允许编译。但是,使用强制转换的结果是未定义的行为。
为了避免T(a)
等效于强制转换的意外情况,请使用新的 C++11 统一初始化语法T{a}
,它始终是初始化,而不是强制转换表达式。
很好的问题,调查和回答它向我展示了一个我以前不知道的新问题,感谢 JaredC 和 Dietmar 的新知识!
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 将成员函数的返回类型引用到C++中的自定义类
- 非类型引用参数可以在运行时修改,这是否意味着模板可以在运行时实例化?
- C++:类类型引用运算符=用法
- 将 const 类型引用对象注册为类成员对象C++
- 错误:绑定到类型引用会丢弃限定符
- 如果作为基类型引用传递,派生类型会解构吗
- 未分配返回未定义对象类型引用的 C++ 函数的返回值时会发生什么情况
- 类型引用的初始化无效
- C++ 从函数返回多个类型引用并将它们强制转换为我们需要的类型
- 函数常量返回类型:类型引用的初始化无效
- 将类型的嵌套类型引用为类模板的参数的问题
- 与返回类型(引用、常量引用)混淆
- 调用具有const键类型引用的std::指针集的count方法
- 返回运算符类型=-引用或值
- 非类型引用形参/实参
- c++中定义不同类型引用的区别
- 为什么返回类型引用输出流
- 非类型(引用)模板参数和链接
- 类型引用的初始化无效