为什么内联用户提供的构造函数odr使用基类构造函数? [英] Why does an inline user-provided constructor odr-uses base class constructors?
问题描述
考虑以下说明性示例
#include <iostream>
template <typename>
struct Base {
static int const touch;
Base() {
(void)touch;
}
};
template<typename CRTP>
int const Base<CRTP>::touch = []{
std::cout << "Initialized!\n";
return 0;
}();
struct A : Base<A> {
A() {}
};
struct B : Base<B> {
B() = default;
};
int main() {
}
当上述程序由 GCC 编译时, VC ++ 并执行,一个人始终看到以下输出:
When the above program is compiled by GCC, Clang or VC++ and executed, one consistently sees the following output:
Initialized!
所有三个编译器均发出 Base< A> :: touch
的定义和初始化,而两个编译器均不发出 Base< B> :: touch
的定义和初始化(也通过Godbolt验证).因此,我可以得出结论,这是标准的认可行为.
All three compilers emit the definition and initialization of Base<A>::touch
, whereas neither emits the definition and initialization of Base<B>::touch
(verified also via godbolt). So I would conclude this is standard sanctioned behavior.
对于 B
的默认构造函数,我们有
For the defaulted constructor of B
, we have
[class.ctor]
7 默认构造函数,而不是默认构造函数当它被用于创建其类类型的对象([intro.object])或在其第一次声明后被明确默认时,将隐式定义为delete.
7 A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used to create an object of its class type ([intro.object]) or when it is explicitly defaulted after its first declaration.
从中可以得出结论,由于在我们的TU中都不适用任何条件,因此永远不会隐式定义 B :: B()
.因此,它永远不会使用 Base< B> :: Base()
和 Base< B> :: touch
.我觉得这很合理.
From which one may conclude that since neither condition applies in our TU, B::B()
is never implicitly defined. So it never odr-uses Base<B>::Base()
and Base<B>::touch
. I find this reasonable.
但是,我不明白为什么 A :: A()
最终会使用其基类的成员进行odr.我们知道
However, I cannot understand why A::A()
ends up odr-using the members of its base class. We know that
[class.mfct]
1 成员函数可以在其定义中类定义,在这种情况下,它是一个内联成员函数...
1 A member function may be defined in its class definition, in which case it is an inline member function ...
[dcl.inline]
6 应该定义一个内联函数或变量在每个使用该翻译单位的翻译单位中,并且在每种情况下都应具有完全相同的定义([basic.def.odr]).
6 An inline function or variable shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case ([basic.def.odr]).
[basic.def.odr]
4 ...的构造函数按照[dcl.init]中指定的方式使用一个类.
4 ... A constructor for a class is odr-used as specified in [dcl.init].
我们从不初始化任何类型为 A
的对象,因此我们不应该使用其构造函数进行odr.因此,我们的程序最终不会包含 A :: A()
的任何定义.
We never initialize any objects of type A
, so we shouldn't be odr-using its constructor. And so our program wouldn't end up containing any definition of A::A()
.
那么为什么它的行为就像定义一样存在?为什么它会使用 Base< A> :: Base()
并导致其实例化?
So why does it behave as though a definition exists? Why does it odr-use Base<A>::Base()
and causes its instantiation?
推荐答案
对于odr使用 Base< T> :: Base
的 any 内联定义,会发生这种情况例如:
This happens for any inline definition that odr-uses Base<T>::Base
, for example:
inline void x() {
Base<char>();
}
struct A : Base<A> {
A(int) {}
void x() {
Base<int>();
}
};
struct C : Base<C> {
C();
};
inline C::C() = default; // See [1]
// Will print "Initialized!" four times
B()=默认
不能使用 Base< T> :: Base
,因为它仅定义为 [basic.def]/2 ,它不是发射"的.由于[class.ctor]/7(如您所引用).仅当(并且)当对 B :: B()
本身进行了odr使用时,才会(隐式)定义将使用 Base< T> :: Base
的定义.
B() = default
does not odr-use Base<T>::Base
because it is only defined as defaulted. Even though structurally a definition according to [basic.def]/2, it is not "emitted" because of [class.ctor]/7 (as you quoted). The definition that would odr-use Base<T>::Base
will only be (implicitly) defined if and when B::B()
is odr-used itself.
对于定义的其他内联函数,不存在这样的豁免.它们的定义无条件(且在结构上)包含odr-use Base< T> :: Base
.在您的示例中, A :: A()
是一个定义,而您的程序确实包含一个 A :: A()
的定义,该定义使用 Base< T> :: Base
.
For other inline functions that are defined, there does not exist such an exemption. Their definitions unconditionally (and structurally) contain an odr-use Base<T>::Base
. A::A()
in your example is a definition, and your program does contain a definition of A::A()
that uses Base<T>::Base
.
"应在使用了内联函数或变量的每个翻译单元中定义内联函数或变量"..这是必须"处理.要求(对于每个使用内联函数的TU,都需要一个定义),而不是使用内联函数的odr的结果.
"An inline function or variable shall be defined in every translation unit in which it is odr-used". This is a "shall" requirement (for every TU in which an inline function is odr-used, a definition is required), not the consequence of odr-using an inline function.
[1]作为 [dcl.fct.def.default]/5 :
在显式默认的位置定义了用户提供的显式默认函数(即在第一次声明后显式默认)
A user-provided explicitly-defaulted function (i.e., explicitly defaulted after its first declaration) is defined at the point where it is explicitly defaulted
因此, C :: C()
具有默认定义,该默认定义会立即生成隐式"信息.定义.
So C::C()
has a default definition which immediately generates the "implicit" definition.
这篇关于为什么内联用户提供的构造函数odr使用基类构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!