使用引用作为模板类型

时间:2012-12-17 00:40:20

标签: c++

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

我在这里缺少什么?

2 个答案:

答案 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的新知识!