使用 static_cast<>() 声明变量时使用 auto 的目的是什么?
what is the purpose of using auto when declaring variable with static_cast<>()?
Scott Meyers 在他的 "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" 中讨论了 auto
在不同情况下的使用。他指出,有时 auto
会扣除不正确的类型,因为通常情况下,开发人员会(可能无意识地)使用隐式转换,如下所示:
std::vector<bool> vec = {true, false};
bool a = vec[0]
像这样使用 auto
时:
std::vector<bool> vec = {true, false};
auto a = vec[0]
会使 a
变成 std::vector<bool>::reference
所以作者建议在赋值之前转换它:
auto a = static_cast<bool>(vec[0])
我不明白如果我可以简单地依靠隐式转换,为什么我会以这种方式使用 auto
和 static_cast<>
。我认为这可能是为了强调正在进行转换的事实(明确指出),但对我来说它仍然看起来有点矫枉过正。这种解决方案的优势是什么?
干杯!
在许多情况下,static_cast
可以帮助减少编译器的歧义,也可以帮助减少 reader 与 auto
一起使用时的歧义。
具体来说,在考虑例子中的std::vector<bool>
时,我可以想到两种这样的情况:
- 如果将其传递给推导参数的函数模板,您可能宁愿
decltype(a)
成为 bool
而不是某种 std::__vector_bool_reference_wrapper
类型,或者
- 如果将
a
传递给具有接受 bool&
或 bool*
的签名的函数,您会希望它是正确的类型——因为隐式转换不会发生
上述情况适用于任何可能具有隐式转换的事物,而不仅仅是 bool
/reference-wrapper。
此外,其他类型的案件会变得更有趣。
指针:
nullptr
属于 decltype(nullptr)
类型,也称为 std::nullptr_t
。这是不是任何类型T*
。这意味着您不能编写如下代码:
auto p = nullptr;
...
p = &a; // compile-error!
而是需要:
auto p = static_cast<T*>(nullptr);
...
p = &a; // works!
无意促销
无意的推广会产生意想不到的错误。如果代码使用 auto
并且依赖于整数溢出,而不明确类型,则可能会无意中产生整数提升——这可以防止溢出发生。这可能会在某些代码中产生细微的错误。
float
/double
晋升也可能发生同样的情况,尽管我很难想到这种情况会是负面的。
如果将结果传递给一个函数,该函数期望引用或指向 T
的类型与提升类型不同(类似于 vector<bool>
上面的例子)。
我确定存在其他情况,其中 static_cast
在与 auto
一起使用时很重要,但一般来说,想到的情况涉及重载决策和模板附带的严格类型类型推导。
除此之外,在某些情况下,static_cast
只是有助于使用大量 auto
的复杂函数的一般可读性
以此为前提:你要尽量用auto
,那么
std::vector<bool> vec = {true, false};
auto a = vec[0];
会做出意想不到的事情,同时:
auto a = static_cast<bool>(vec[0]);
会给你一个bool
。我认为这里的重点不是说:"Use static_cast
together with auto
as much as possible"。而是:"If you want to use auto
almost always, then sometimes you have to add a static_cast
"
...in this way if I can simply count on implicit conversion...
在这种情况下是的,但是您没有使用 auto
。还要考虑不是您使用 auto
的情况。假设您得到一个定义为:
的 lambda
auto foo = [](auto x){};
您无法更改其签名,因此如果您想使用 vec[0]
调用它并推导出正确的类型,则需要使用 static_cast
。
还要考虑,如果您遵循 AAA(几乎总是自动),那么您确实希望将所有变量声明为 auto
。这有助于永远不会忘记初始化变量。如果你回到
bool a = vec[0];
当需要时,这就打败了首先应用 AAA 的全部意义。您希望保持一致,而不是根据初始化程序选择 auto
与显式类型。
Scott Meyers 在他的 "Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14" 中讨论了 auto
在不同情况下的使用。他指出,有时 auto
会扣除不正确的类型,因为通常情况下,开发人员会(可能无意识地)使用隐式转换,如下所示:
std::vector<bool> vec = {true, false};
bool a = vec[0]
像这样使用 auto
时:
std::vector<bool> vec = {true, false};
auto a = vec[0]
会使 a
变成 std::vector<bool>::reference
所以作者建议在赋值之前转换它:
auto a = static_cast<bool>(vec[0])
我不明白如果我可以简单地依靠隐式转换,为什么我会以这种方式使用 auto
和 static_cast<>
。我认为这可能是为了强调正在进行转换的事实(明确指出),但对我来说它仍然看起来有点矫枉过正。这种解决方案的优势是什么?
干杯!
在许多情况下,static_cast
可以帮助减少编译器的歧义,也可以帮助减少 reader 与 auto
一起使用时的歧义。
具体来说,在考虑例子中的std::vector<bool>
时,我可以想到两种这样的情况:
- 如果将其传递给推导参数的函数模板,您可能宁愿
decltype(a)
成为bool
而不是某种std::__vector_bool_reference_wrapper
类型,或者 - 如果将
a
传递给具有接受bool&
或bool*
的签名的函数,您会希望它是正确的类型——因为隐式转换不会发生
上述情况适用于任何可能具有隐式转换的事物,而不仅仅是 bool
/reference-wrapper。
此外,其他类型的案件会变得更有趣。
指针:
nullptr
属于 decltype(nullptr)
类型,也称为 std::nullptr_t
。这是不是任何类型T*
。这意味着您不能编写如下代码:
auto p = nullptr;
...
p = &a; // compile-error!
而是需要:
auto p = static_cast<T*>(nullptr);
...
p = &a; // works!
无意促销
无意的推广会产生意想不到的错误。如果代码使用 auto
并且依赖于整数溢出,而不明确类型,则可能会无意中产生整数提升——这可以防止溢出发生。这可能会在某些代码中产生细微的错误。
float
/double
晋升也可能发生同样的情况,尽管我很难想到这种情况会是负面的。
如果将结果传递给一个函数,该函数期望引用或指向 T
的类型与提升类型不同(类似于 vector<bool>
上面的例子)。
我确定存在其他情况,其中 static_cast
在与 auto
一起使用时很重要,但一般来说,想到的情况涉及重载决策和模板附带的严格类型类型推导。
除此之外,在某些情况下,static_cast
只是有助于使用大量 auto
以此为前提:你要尽量用auto
,那么
std::vector<bool> vec = {true, false};
auto a = vec[0];
会做出意想不到的事情,同时:
auto a = static_cast<bool>(vec[0]);
会给你一个bool
。我认为这里的重点不是说:"Use static_cast
together with auto
as much as possible"。而是:"If you want to use auto
almost always, then sometimes you have to add a static_cast
"
...in this way if I can simply count on implicit conversion...
在这种情况下是的,但是您没有使用 auto
。还要考虑不是您使用 auto
的情况。假设您得到一个定义为:
auto foo = [](auto x){};
您无法更改其签名,因此如果您想使用 vec[0]
调用它并推导出正确的类型,则需要使用 static_cast
。
还要考虑,如果您遵循 AAA(几乎总是自动),那么您确实希望将所有变量声明为 auto
。这有助于永远不会忘记初始化变量。如果你回到
bool a = vec[0];
当需要时,这就打败了首先应用 AAA 的全部意义。您希望保持一致,而不是根据初始化程序选择 auto
与显式类型。