自动和静态类型转换——很好的实践

auto and static_casts - good practice

本文关键字:很好 类型转换 静态      更新时间:2023-10-16

在Scott Meyer的《Effective Modern c++》一书中,我们可以读到:

std::vector<bool> features(const Widget& w);
Widget w;
…
bool highPriority = features(w)[5];
…
processWidget(w, highPriority); 

和auto

选项
auto highPriority = features(w)[5];

导致未定义的行为,因为features()返回std::vector<bool>,当从opearator[]返回值时使用std::vector<bool>::reference类型的代理对象。

作为一个解决方案,建议不要停止使用auto,而是使用static_casts

所以Scott Meyers建议使用:

auto highPriority = static_cast<bool>(features(w)[5]);

代替:

bool highPriority = features(w)[5];

我的问题是:这两者的真正区别是什么?在我看来,这两种方法是相同的,因为这两种方法都以完全相同的方式使重构变得更加困难(改变函数特性中的返回值类型并不会使变量highPriority成为不同的类型),而且第二种方法更短。

如果您不喜欢features的界面,您可以将其隐藏在辅助函数中

bool is_high_priority(const Widget& w)
{ return features(w)[5]; }

和现在的

auto highPriority = is_high_priority(w);

如果features是一个返回std::vector<bool>的函数,

auto highPriority = features(w)[5];

存储逻辑引用。存储对象指向一个不再存在的向量。使用它会导致未定义行为。

而不是做

bool const highPriority = features(w)[5];

auto const highPriority = !!features(w)[5];

或者Scott推荐的–但对我的口味来说太啰嗦了。使用static_cast .

存储的对象现在是bool

这三种表达同一声明的方式在功能上没有区别。唯一的区别是非功能性的:在我看来,static_cast不必要的冗长,!!可能会抑制来自一个通用编译器的关于性能的愚蠢警告。

当您使用auto时,auto将其推断为highPriority返回的类型,highPriority是对bool的引用。问题是,highPriority返回的不是bool对象的引用,而是std::vector::引用对象。('reference'是std::vector中的嵌套类)。Std::vector::reference是一个"代理类",一个模仿其他类型行为的类。它不仅是一个代理类,而且是一个"不可见"的代理类。这样的类不能很好地与auto一起工作。Auto不能正确地推断不可见代理类的类型。但是static_cast强制将高优先级转换为bool类型。这避免了未定义行为。