- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我最近从 Scott Meyers 那里购买了新的 Effective现代 C++ 并通读了它。但是我遇到了一件让我非常烦恼的事情。
在第 5 项中,Scott 说使用 auto
是一件很棒的事情。它可以节省输入,在大多数情况下为您提供正确的类型,并且可能不受类型不匹配的影响。我完全理解这一点并想到了 auto
也是一件好事。
但是在第 6 项中,斯科特说每个硬币都有两个面。同样,可能存在 auto
的情况推导出完全错误的类型,例如用于代理对象。
你可能已经知道这个例子:
class Widget;
std::vector<bool> features(Widget w);
Widget w;
bool priority = features(w)[5]; // this is fine
auto priority = features(w)[5]; // this result in priority being a proxy
// to a temporary object, which will result
// in undefined behavior on usage after that
// line
auto priority = static_cast<bool>(features(w)[5]);
auto
的两个优势在显式给定类型上。
auto priority = static_cast<bool>(features(w)[5]);
bool priority = features(w)[5];
Guideline: Consider declaring local variables auto x = type{ expr }; when you do want to explicitly commit to a type. It is self-documenting to show that the code is explicitly requesting a conversion, it guarantees the variable will be initialized, and it won’t allow an accidental implicit narrowing conversion. Only when you do want explicit narrowing, use ( ) instead of { }.
bool priority = features(w)[5];
auto priority = static_cast<bool>(features(w)[5]);
auto priority = bool(features(w)[5]);
auto priority = bool{features(w)[5]};
最佳答案
遵循 C++ 标准:
§ 8.5 Initializers
[dcl.init]
The initialization that occurs in the form
T x = a;
as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization.
auto x = features(w)[5];
template <typename A>
void foo(A x) {}
foo(features(w)[5]);
auto bar()
{
return features(w)[5];
}
auto lambda = [] (auto x) {};
lambda(features(w)[5]);
static_cast<T>
移动到赋值的左侧”。
/*1*/ foo(static_cast<bool>(features(w)[5]));
/*2*/ return static_cast<bool>(features(w)[5]);
/*3*/ lambda(static_cast<bool>(features(w)[5]));
static_cast<T>
是一种强制所需类型的优雅方式,或者可以通过显式构造函数调用来表示:
foo(bool{features(w)[5]});
Whenever you want to force the type of a variable, use
auto x = static_cast<T>(y);
instead ofT x{y};
.
The type inference with
auto
is cool, but may end up with undefined behavior if used unwisely.
If the compiler's regular type-deduction mechanism is not what you want, use
static_cast<T>(y)
.
bool priority = features(w)[5];
auto priority = static_cast<bool>(features(w)[5]);
auto priority = bool(features(w)[5]);
auto priority = bool{features(w)[5]};
std::vector<bool>::reference
是
不是隐含的 可转换为
bool
:
struct BoolReference
{
explicit operator bool() { /*...*/ }
};
bool priority = features(w)[5];
将
不编译 ,因为它不是一个明确的 bool 上下文。其他的会正常工作(只要
operator bool()
是可访问的)。
std::vector<bool>::reference
以旧方式实现,尽管转换运算符不是
explicit
,它返回
int
反而:
struct BoolReference
{
operator int() { /*...*/ }
};
auto priority = bool{features(w)[5]};
初始化,如使用
{}
防止缩小(将
int
转换为
bool
是)。
bool
呢?完全没有,但关于一些用户定义的类型,令我们惊讶的是,声明
explicit
构造函数:
struct MyBool
{
explicit MyBool(bool b) {}
};
MyBool priority = features(w)[5];
初始化将
不编译 ,因为复制初始化语法需要非显式构造函数。其他人会工作。
auto priority = bool{features(w)[5]};
features(w)[5]
真的是 .
auto x = T{y};
的显式类型初始化器的观点。形式(尽管它与
auto x = static_cast<T>(y)
不同,因此并非所有参数都适用)超过
T x{y};
, 哪个是:
auto
变量必须始终被初始化。也就是说,你不能写auto a;
,就像你可以写容易出错的 int a;
auto f = 3.14f;
// ^ float
auto s = "foo"s;
// ^ std::string
auto func(double) -> int;
auto func = [=] (double) {};
using dict = set<string>;
template <class T>
using myvec = vector<T, myalloc>;
auto x = T{y};
<category> name = <type> <initializer>;
T x{y}
相比,使用复制省略和非显式复制/移动构造函数,它的成本为零。句法。 unique_ptr<Base> p = make_unique<Derived>(); // subtle difference
auto p = unique_ptr<Base>{make_unique<Derived>()}; // explicit and clear
{}
保证没有隐式转换和缩小。 auto x = T{}
的一些缺点。一般形式,在这篇文章中已经描述过:
auto x = std::atomic<int>{}; // fails to compile, copy constructor deleted
-fno-elide-constructors
),则移动不可移动类型会导致昂贵的复制: auto a = std::array<int,50>{};
关于c++ - 为什么我更喜欢 "explicitly typed initializer"成语而不是明确给出类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25607216/
我被指出“安全 bool 成语”,在试图破译发生了什么之后(解释 supplied on the site 不足以让我理解它为什么起作用),我决定尝试将以下代码分开并尝试尽可能地简化它。该网站提供的代
访问标量表达式的最简洁和字节码有效的方法是什么 多次从另一个表情的深处? 以下代码中的所有函数(例如 scalar4 )都可以根据需要运行。但只有 字节编码器 发出高效的字节码(尽管它以 ISTORE
我正在处理一个 Chart 类,它有一个 margin 参数,它包含 :top、:bottom、:right 和 :left 值。我的第一个选择是使 margin 成为 setter 并像这样设置值:
想象一下,您正在使用明显的蛮力算法生成斐波那契数列。如果我知道我想提前生成的斐波那契数,我可以使用幂连接 ^: 做这样的事情: (, [: +/ _2&{.)^:20 i.2 当斐波那契数达到某个极限
有很多地方(例如 How to use requestAnimationFrame? )修复了 window.requestAnimationFrame 如下。我不明白为什么赋值的右侧包含在函数调用中
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我已经使用 idiorm 玩了几天了,并且逐渐设法让它真正开始执行查询。虽然我遇到了一些奇怪的事情,但我无法弄清楚。 find_many() 函数只返回一条记录,它始终是数据库中的最后一条记录。例如,
我读到 Pimpl 有利于二进制兼容性,接口(interface)有利于轻松切换实现。我需要结合这两种技术,让我的应用程序能够通过配置文件切换底层实现。 以下是我当前的设计布局: 类 Foo:提供面向
今天我了解了 C++“memberspace”惯用语,它粗略地滥用了 C++ 的一个属性,该属性使 T::bar 以及 T.bar 工作,当T 在某些范围内既是类型又是对象。 struct A {
这个 jQuery 片段最清楚的常用习惯用法是什么? $('#someTextarea').val( $('#someTextarea').val() + someString ); 将原始代码包装在
我记得很久以前读过有关复杂对象配置情况下的 C++ 构造函数习惯用法。它特别有用,因为它有助于为一些讨厌的概念启用 RAII,这些概念方式太多(通常是相互冲突的)选项。 这是一个简单的例子。假设您要为
boost 库是否提供了安全 bool 习惯用法的实现,以便我可以从中派生我的类? 如果是 - 它在哪里? 如果不是 - 除了我自己实现之外,我还有哪些选择? 我发现了以下类似的问题:“Is ther
我想使用 pimpl idiom 和继承。 这里是基础公共(public)类及其实现类: class A { public: A(){pAImpl = new AImpl;};
通过使用 Copy & Swap我们可以轻松实现具有强大异常安全性的复制分配: T& operator = (T other){ using std::swap; swap(*this
这个问题在这里已经有了答案: Iterating over every two elements in a list [duplicate] (22 个回答) 关闭3年前。 我觉得我花了很多时间用 P
关于 pimpl idiom 有一些关于 SO 的问题,但我更好奇它在实践中的使用频率。 我了解在性能和封装之间需要权衡取舍,另外由于额外的重定向会导致一些调试烦恼。 这样,这是应该在每个类(clas
这个问题在这里已经有了答案: Is the PIMPL idiom really used in practice? (12 个回答) 关闭7年前。 背景: PIMPL Idiom (指向 IPLem
这是网络上最常见的实现方式 private static class LazySomethingHolder { public static Something something = new S
像std::iterator_traits 这样的包罗万象的特征类通过将类型的属性与其定义分开是很有用的,例如,可以在定义完成之前使属性可用。 除了每个客户端类本身之外还定义特征是不方便的,因为特征通
我通常为 pimpl 使用 boost::scoped_ptr(出于一个原因,因为如果我忘记处理复制构造函数,我不会感到惊讶) 然而,对于模板,我不能只将析构函数放在完全定义了 impl 的 cpp
我是一名优秀的程序员,十分优秀!