难以理解零法则中的 C++11 语法

Trouble understanding the C++11 syntax in the Rule of Zero

本文关键字:C++11 语法      更新时间:2023-10-16

我正在研究零法则,对演示该规则的最后一段代码有 2 个问题。

class module {
    public:
        explicit module(std::wstring const& name)
        : handle { ::LoadLibrary(name.c_str()), &::FreeLibrary } {}
    
        // other module related functions go here
    
    private:
        using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;
    
        module_handle handle;
    };
  1. 为什么使用大括号而不是括号来初始化句柄?
  2. 在这种情况下,使用 module_handle = std::unique_ptr<void,>; 到底是什么意思? 是否可以用 typedef 替换它?

为什么使用大括号而不是括号来初始化句柄?

这是 C++11 中引入的统一初始化方法

在这种情况下,使用 module_handle = std::unique_ptr; 究竟意味着什么?是否可以用 typedef 替换它?

它是模板别名,也用于创建新类型。 usingtypedef <</p>

div class="answers" 的全新强大替代品>
explicit module(std::wstring const& name)
    : handle { ::LoadLibrary(name.c_str()), &::FreeLibrary }

1) 这是 C++11 的新(统一)初始值设定项列表语法。 它将 2 个参数传递给构造函数,该函数将初始化变量 handle 。 在这种情况下,它实际上与

explicit module(std::wstring const& name)
    : handle(::LoadLibrary(name.c_str()), &::FreeLibrary)

它将调用std::unique_ptr的构造函数,该构造函数采用"指针"(在本例中为句柄)和删除器(FreeLibrary的地址)。

using module_handle = std::unique_ptr<void, decltype(&::FreeLibrary)>;

2)这基本上与typedef相同。 有关详细信息,请参阅此处。

  1. 为什么使用大括号而不是括号来初始化句柄?

其他人已经说了大括号是什么(统一初始化),但没有人解释为什么当括号应该同样工作时,人们会在这里使用它。

这个想法是,C++11 不是学习所有不同的初始化语法,而是使人们能够简单地学习一种语法并在任何地方使用它;统一初始化是添加的功能之一,目的是使编写C++更容易(以及其他原因)。

需要注意的一点是,统一初始化是统一的,因为它适用于所有初始化上下文,并且可以执行不同类型的初始化(例如,聚合初始化与使用构造函数),但这并不意味着可以使用它完成任何初始化;具体来说,在少数情况下,可以定义类型,以便统一初始化无法访问某些构造函数。答案是根本不应该编写这样的构造函数。不幸的是,有些已经内置到标准库中,vector<int>(4, 5) vs. vector<int>{4, 5}是常见的例子。

2. 在这种情况下,使用 module_handle = std::unique_ptr; 到底是什么意思? 是否可以用 typedef 替换它?

这只是 typedef 的不同语法。该语法比 typedef 更强大,因为它可以模板化,但在这种情况下不使用。此示例可以使用 typedef 实现。

首选新语法的原因是因为它是一种更以类型为中心、类似C++的语法。

旧的 typedef 语法使用(并且根据许多人的说法,遭受)C 的"声明模仿使用"规则;也就是说,使用指针看起来像*ptr,因此声明指针使用相同的表达式,int *ptr; 。使用返回指向函数的指针的函数看起来像(*foo())()因此再次声明一个函数使用相同的表达式,int (*foo())(); .此语法以表达式为中心,您写出一个表达式,语言推断变量的隐含类型。

这种语法的问题在于它混淆了很多人,随着时间的推移,C 和 C++ 都以各种方式进行了更改,这与这个原始理想不一致。例如,用 C 声明一个函数最初严格遵循此规则;在早期版本的 C 中,您可以使用 int foo(x, y) 声明一个函数,该函数完全模仿函数调用表达式foo(x, y)。后来很明显,类型安全和检查很重要,在ISO C中声明一个函数看起来像int foo(int x, int y),这与函数的用法并不那么接近。

C++更进一步,例如介绍参考文献。由于引用用法看起来与使用常规对象没有任何不同,因此没有语法可以添加到声明中以遵循"声明模拟使用"。相反,他们只是决定不遵循规则,而只是选择不会与之冲突的语法。

C++也比C更强调类型;模板按类型,基于类型的重载等进行参数化。

因此,C++11 不仅因为旧语法似乎天生就有问题,也因为C++更重视类型而不是表达式,因此 11 为类型别名引入了这种新语法。而不是晦涩的语法,而是一个简单的using <type alias> = <type>;。不需要"螺旋规则"或"从右到左"规则。

这种语法不仅可以完全替换 typedefs,还可以添加直接模板化的能力,替换长期以来需要的模板类 hack 中的旧 typedef。同样,新语法是一项附加功能,可以更轻松地学习编写C++。