在下面的示例中,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
的返回中构造值会产生编译错误。
我在这里缺少什么?
答案 0 :(得分:6)
首先,问题实际上与模板没有任何关系并不值得,因为这段代码编译了一个井:
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
转化等的案例。)
答案 1 :(得分:5)
这与模板无关,如果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.cast]的规则)将const_cast
如果是static_cast
有效(不是)或static_cast
如果有效(不是)或const_cast
后跟reinterpret_cast
如果有效(不是)或reinterpret_cast
如果有效( )或const_cast
后跟reinterpret_cast
,如果该项有效,则表达式不正确。< / p>
正如Dietmar所说,这与做std::string & s = reinterpret_cast<std::string&>(a);
,即
T(a)
我发现原始代码编译时非常令人惊讶,但由于它与上面的那行相同,所以允许编译。然而,使用强制转换的结果是未定义的行为。
为了避免T{a}
等同于强制转换的意外,请使用新的C ++ 11统一初始化语法{{1}},它始终是初始化,而不是强制转换表达式。
很好的问题,调查和回答它向我展示了一个我以前没有意识到的新问题,感谢JaredC和Dietmar的新知识!