【问题标题】:Are defaulted functions inline functions in C++20?C++20 中的默认函数是内联函数吗?
【发布时间】:2022-12-07 22:00:05
【问题描述】:

在这段代码中:

struct tmp
{
    int va = 0;
    tmp() = default;
    bool operator==(const tmp& rhv) const = default; //(in c++20)
};

构造函数 tmp()operator== 是内联函数,即使我没有在它们前面添加“inline”关键字?

如果答案是肯定的,如果在它们前面加一个“inline”会怎么样呢?

我可以强制它们成为常规函数吗? (虽然我不知道哪个目标文件可以存储它们。)

【问题讨论】:

标签: c++ class struct language-lawyer c++20


【解决方案1】:

构造函数 tmp() 和 operator== 是内联函数,即使我没有在它们前面添加“inline”关键字?

是的,这可以从 dcl.fct.def.def.default#3 中看出:

未定义为 deleted 的显式默认函数只有在与 constexpr 兼容([special]、[class.compare.default])时才可以声明为 constexpr 或 consteval。在其第一个声明中显式默认的函数是隐式内联的([dcl.inline]),如果它是 constexpr 兼容的,则它是隐式 constexpr ([dcl.constexpr])。

(强调我的)

因为 tmp::tmp()bool tmp::operator==(const tmp&) const 都是明确违约在他们各自的第一份声明中,他们都是隐式内联.


如果答案是肯定的,如果在它们前面加一个“inline”会怎么样呢?

由于两者都已经隐式内联,因此在它们前面显式添加 inline 的效果与不显式添加 inline 的效果相同。


我可以强制它们成为常规函数吗?

你可以避免他们成为隐式内联通过在成员函数的第一个声明中不明确默认成员函数,以便上述引用的规则不适用。例如,

struct tmp
{
    int va = 0;
    tmp(); //don't default here in the first declaration
    
};
tmp::tmp() = default;
int main()
{
    tmp t; //the default ctor is not "implicitly inline"
}

【讨论】:

  • 对不起,错误的问题,我更正了它(我可以强制他们......),我可以强制他们成为常规功能吗?
  • @LiiiEW 在它们前面显式添加 inline 不会有任何额外效果,因为它们已经“隐式内联”。
  • 我的意思是我可以强制它们在 C++20 中使用常规函数(不是内联)。
  • @LiiiEW 您可以通过避免在成员函数的第一个声明中显式默认它们来做到这一点,这样上述标准中引用的规则不适用。请参阅我更新的答案,其中我给出了 demo
  • @LiiiEW 您可以按照标准定义的inline 功能来定义它们,但是没有基于标准的方法来防止编译器在任何情况下内联它们。 as-if 规则允许编译器发出内联机器代码,即使是对非inline 函数的调用也是如此。
【解决方案2】:

我不确定这是否是您要查找的内容,但您至少可以避免 inline 的两种含义中的一种(请阅读这两种含义的出色回答:https://stackoverflow.com/a/47931884/11829247)。

如果你在 .h 文件中有这个:

struct Thing
{
 ...
 ~Thing();
}

然后在 .cpp 文件中你有:Thing::~Thing() = default; 那么至少 inlines 含义的链接器部分被禁用,类现在必须遵守一个定义规则。

我在我想要一个不透明的 pimpl 类的程序中使用它,所以我有:

class Thing
{
  struct Fsm;               // forward declare class
  std::unique_ptr<Fsm> fsm; // pimpl with that class
}

如果我未声明 Thing 的析构函数或只是 =default,那么就会出错,因为编译器无法为 unique_ptr 构造析构函数,因为 Fsm 是一个不完整的类。

但是,如果 Thing 的析构函数“延迟”到 .cpp 文件,其中我还包含 Fsm 的标头,那么一切都很好,编译器可以为我创建默认析构函数。

【讨论】:

  • 链接器部分ODR 的一部分。并且您的使用与这部分无关。如果您在定义 Impl 之前在您的 cpp 文件中默认了 d'tor,由于完全相同的原因,它仍然是格式错误的。
猜你喜欢
  • 2012-06-30
  • 2017-01-05
  • 1970-01-01
  • 1970-01-01
  • 2010-09-06
  • 1970-01-01
  • 2017-08-28
  • 2013-03-05
  • 2013-04-15
相关资源
最近更新 更多