7

在下面的示例中,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会产生编译错误。

我在这里想念什么?

4

2 回答 2

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 段:

[其他形式的强制转换] a reinterpret_cast (5.2.10) [...] 执行的转换可以使用显式类型转换的强制转换表示法执行。[...]

(省略涵盖涉及用户定义类型、内置类型转换、const转换等的情况)

于 2012-12-17T00:56:59.230 回答
5

这与模板无关,如果T只是 typedefstd::string&而不是推导的模板参数,则会得到相同的结果:

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

whereT(a)与演员阵容相同,(T)a(std::string&)awhich(根据 5.4 [expr.cast] 的规则const_caststatic_caststatic_cast执行由 a const_castif that's valid (which it is not) 或 a reinterpret_castif that's valid (which it is ) 或 areinterpret_cast后跟 a const_castif that's valid,否则表达式格式错误。

所以正如 Dietmar 所说,这与做 a 是一样的reinterpret_cast,即

std::string & s = reinterpret_cast<std::string&>(a);

我发现原始代码编译非常令人惊讶,但由于它与上面那行相同,因此允许编译。但是,使用强制转换的结果是未定义的行为。

为避免令人惊讶的 whereT(a)等效于强制转换,请使用新的 C++11 统一初始化语法,T{a}它始终是初始化,而不是强制转换表达式。

很好的问题,调查和回答它向我展示了一个我以前不知道的新问题,感谢 JaredC 和 Dietmar 提供的新知识!

于 2012-12-17T00:58:32.723 回答