"= default"是否允许离线实施?
Does "= default" allow out-of-line implementations?
通常我在标头中看到使用的= default
语法。我的理解是,这与函数在标头中显式实现的情况相同,请参见下面的Foo
。
Foo.h
#pragma once
class Foo
{
public:
Foo() = default;
Foo(const Foo& other) = default;
};
纯粹出于好奇,= default
可以在源文件中使用如下吗?
Bar.h
#pragma once
class Bar
{
public:
Bar();
Bar(const Bar& other);
};
Bar.cpp
#include "Bar.h"
Bar::Bar() = default;
Bar::Bar(const Bar&) = default;
据我所知,这相当于显式地实现cpp文件中的函数。
上面的Bar
示例与gcc-5.1
一起编译,但标准允许这种用法吗?
顺便说一句,在源文件中使用= default
与标头相比有什么好处吗?
是的,这是合法的。从[dcl.fct.def.default]
显式默认函数和隐式声明函数统称为默认函数,实现应为它们提供隐式定义(12.1、12.4、12.8),这可能意味着将它们定义为已删除如果函数是用户声明的,并且在第一次声明时没有显式默认或删除,那么它就是用户提供的。用户提供的显式默认函数(即,在其第一次声明后显式默认)是在显式默认的点定义的如果这样的函数被隐式定义为已删除,则表示程序格式不正确。
强调矿
然后他们会详细介绍的具体情况
struct nontrivial1 { nontrivial1(); }; nontrivial1::nontrivial1() = default; // not first declaration
因此,只要函数没有被隐式标记为已删除,那么函数就会被定义为显式默认的函数
顺便说一句,在源文件中使用
= default
与头文件相比有什么好处吗?
我能看到的唯一"优势"是,它允许现有的代码库更改其cpp文件,以使用现代技术,而不必更改头文件。标准中甚至有一条注释:
注意:在函数的第一次声明后将其声明为默认值,可以提供高效的执行和简洁的定义,同时为不断发展的代码库提供稳定的二进制接口。
在源文件中默认而不是在头文件中默认的一个潜在用途是在unique_ptr
中使用pimpl习惯用法。它需要一个完整的类型来构造和销毁,所以不能在头中定义那些特殊的成员。你必须做:
Foo.h
struct Foo {
struct Impl;
unique_ptr<Impl> p;
Foo();
~Foo();
};
Foo.cpp
// Foo::Impl definition here
// now Impl isn't incomplete
Foo::Foo() = default;
Foo::~Foo() = default;
是的,特殊成员函数可能默认为"越界";编译器将生成正确的代码,它将按预期工作。
事实上,有一条规则是关于特殊成员在第一次声明时不被默认的,然后它们被认为是用户提供的(因此不是微不足道的)。
如果函数是用户声明的,并且在第一次声明时没有显式默认或删除,则该函数是用户提供的。用户提供的显式默认函数(即,在其第一次声明后显式默认)是在显式默认的点定义的;如果这样的函数被隐式定义为已删除,那么程序就是格式错误的。
链接到这里[dcl.fct.def.default]。下面的例子详细说明了你的情况;
struct nontrivial1 { nontrivial1(); }; nontrivial1::nontrivial1() = default; // not first declaration
它的有用性在于它所做的事情,它提供了默认的实现,但不是在声明时,因此使它成为用户提供的。如前所述,这在处理尚未完成的类型时非常有用,例如在使用皮条客习语时。它还可以用于将您的类型标记为非平凡类型,从而禁止在需要平凡类型的代码中使用它(例如std::is_trivial
)。
行为发生了微小变化。Bar.cpp
以外的其他TU看不到它们是默认的,因为它们只看到标头。因此,在cpp中放置默认值将使您的类不可平凡地赋值,也不可平凡的构造。
在某些情况下,您需要这样做:如果您的类将unique_ptr
保存为不完整类型,那么在cpp中默认析构函数是一种很好的做法,因为如果您不这样做,则使用您的类的类将需要不完整类型的析构函数可见。
在源文件中实现时,方法不再是默认,而是用户提供。
- QWebEngine 5.7.1 离线导航加载缓存
- ActiveMq:持久队列和离线系统
- 如何离线安装熊猫和依赖项
- QT离线安装程序和兼容的C 编译器安装
- 'tedt'的离线定义
- 离线 Qt 文档
- 如何在QML(Qt)中离线运行OpenStreetMap
- CMAKE:外部项目更新和离线工作
- 如何在没有相机的情况下使用 Kinect 捕获的 RGB-D(请离线流示例代码)
- 缓存Google Maps供离线使用
- 离线嵌入式实时路由
- 可以使用缓存使QML应用程序“离线支持”
- "= default"是否允许离线实施?
- c++ -为离线VS2013加载微软符号
- Postgresql服务器和客户端离线模式
- 离线虚拟方法
- 如何创建离线数据库与c++一起使用
- 如何得到一个距离矩阵的计算正在离线上我的服务器
- 基于订阅的软件许可-离线验证
- 离线时的NetGroupEnum()