auto 和 static_casts - 好的做法
auto and static_casts - good practice
在 Scott Meyer 的 Effective Modern C++ 一书中,我们可以读到:
std::vector<bool> features(const Widget& w);
Widget w;
…
bool highPriority = features(w)[5];
…
processWidget(w, highPriority);
和自动选项
auto highPriority = features(w)[5];
这会导致未定义的行为,因为 features()
是 returning std::vector<bool>
,当 [=35= 时使用 std::vector<bool>::reference
类型的代理对象] 从 opearator[]
.
中获取一个值
作为解决方案,建议不要停止使用 auto
,而是使用 static_casts
.
Scott Meyers 建议使用:
auto highPriority = static_cast<bool>(features(w)[5]);
而不是:
bool highPriority = features(w)[5];
我的问题是:
这两者之间的真正区别是什么?在我看来,两者都是一样的,因为这两种方法都以完全相同的方式使重构变得更加困难(在函数特性中更改 return 值类型不会使变量 highPriority 成为不同的类型),而第二种方法编写起来更短。
用features
一个函数returns一个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
不必要的冗长,以及 !!
可能会抑制来自一个常见编译器的关于性能的愚蠢警告。
如果你不喜欢features
的界面,你可以在辅助函数中隐藏丑陋
bool is_high_priority(const Widget& w)
{ return features(w)[5]; }
现在你的
auto highPriority = is_high_priority(w);
按预期工作。
当您使用 auto 时,auto 将其推断为由 highPriority 编辑的 return 类型,highPriority 是对 bool 的引用。问题是,highPriority 不是 return 对 bool 的引用,而是 std::vector::reference 对象。 ('reference' 是 std::vector 内的嵌套 class)。 std::vector::reference 是一个 "proxy class",一个模拟其他类型行为的 class。它不仅是代理 class,而且是 "invisible" 代理 class。这样的 classes 不适用于自动。 Auto 无法正确推断出不可见代理的类型 class。但是 static_cast 强制将高优先级转换为 bool。这避免了未定义的行为。
在 Scott Meyer 的 Effective Modern C++ 一书中,我们可以读到:
std::vector<bool> features(const Widget& w);
Widget w;
…
bool highPriority = features(w)[5];
…
processWidget(w, highPriority);
和自动选项
auto highPriority = features(w)[5];
这会导致未定义的行为,因为 features()
是 returning std::vector<bool>
,当 [=35= 时使用 std::vector<bool>::reference
类型的代理对象] 从 opearator[]
.
作为解决方案,建议不要停止使用 auto
,而是使用 static_casts
.
Scott Meyers 建议使用:
auto highPriority = static_cast<bool>(features(w)[5]);
而不是:
bool highPriority = features(w)[5];
我的问题是: 这两者之间的真正区别是什么?在我看来,两者都是一样的,因为这两种方法都以完全相同的方式使重构变得更加困难(在函数特性中更改 return 值类型不会使变量 highPriority 成为不同的类型),而第二种方法编写起来更短。
用features
一个函数returns一个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
不必要的冗长,以及 !!
可能会抑制来自一个常见编译器的关于性能的愚蠢警告。
如果你不喜欢features
的界面,你可以在辅助函数中隐藏丑陋
bool is_high_priority(const Widget& w)
{ return features(w)[5]; }
现在你的
auto highPriority = is_high_priority(w);
按预期工作。
当您使用 auto 时,auto 将其推断为由 highPriority 编辑的 return 类型,highPriority 是对 bool 的引用。问题是,highPriority 不是 return 对 bool 的引用,而是 std::vector::reference 对象。 ('reference' 是 std::vector 内的嵌套 class)。 std::vector::reference 是一个 "proxy class",一个模拟其他类型行为的 class。它不仅是代理 class,而且是 "invisible" 代理 class。这样的 classes 不适用于自动。 Auto 无法正确推断出不可见代理的类型 class。但是 static_cast 强制将高优先级转换为 bool。这避免了未定义的行为。