难以理解零规则中的 C++11 语法 [已关闭]

Trouble understanding the C++11 syntax in the Rule of Zero [closed]

提问人:goldcode 提问时间:11/13/2013 最后编辑:Glorfindelgoldcode 更新时间:6/13/2022 访问量:953

问:


想改进这个问题吗?通过编辑这篇文章来更新问题,使其仅关注一个问题。

去年关闭。

我正在研究零法则,并且对演示该规则的最后一段代码有 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, decltype(&::FreeLibrary)>有什么作用;确切地说是在这种情况下?是否可以用 typedef 替换它?
C++ C++11 习语 零法

评论


答:

7赞 masoud 11/13/2013 #1

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

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

使用 module_handle = std::unique_ptr 有什么作用;确切地说是在这种情况下?是否可以用 typedef 替换它?

它是模板别名,也用于创建新类型。 是一个新的和强大的替代品usingtypedef

评论

0赞 goldcode 11/13/2013
@M.M“使用是typedef的新替代品”也是从C++11开始的?
0赞 masoud 11/13/2013
@goldcode:是的,我强烈建议你阅读这篇文章
3赞 Zac Howland 11/13/2013 #2
explicit module(std::wstring const& name)
    : handle { ::LoadLibrary(name.c_str()), &::FreeLibrary }

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

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

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

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

2)这与typedef基本上是一回事。有关详细信息,请参阅此处

3赞 bames53 11/13/2013 #3
  1. 为什么使用大括号而不是括号来初始化句柄?

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

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

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

2. 使用 module_handle = std::unique_ptr 有什么作用;确切地说是在这种情况下?是否可以用 typedef 替换它?

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

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

旧的 typedef 语法使用(并且受到许多人认为)C 语言的“声明模仿使用”规则;也就是说,使用指针类似于 ,因此声明指针使用相同的表达式 。使用返回指向函数的指针的函数,因此再次声明一个函数使用相同的表达式 .这种语法以表达式为中心,您写出一个表达式,语言推导出变量的隐含类型。*ptrint *ptr;(*foo())()int (*foo())();

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

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

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

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

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

评论

0赞 Alexandre C. 11/13/2013
大括号初始值设定项不会选择显式构造函数,并且可用的类型转换也较少(并且您确实希望大多数构造函数都是显式的)。我不会扔掉好的初始值设定器。它们与新的一起使用。
1赞 bames53 11/13/2013
@AlexandreC。您可以使用 not using copy-initialization 来获取显式初始值设定项 (而不是 copy-initialization 使用直接初始化 )。我还认为避免大多数转换是一件好事。Type{x}{x}S s = {x}S s{x}