i前几天正在阅读C 文档,并注意到,尽管字面类型不得具有虚拟成员,但这并不能阻止它们实现实现虚拟成员。或至少这就是我所理解的。
这是我一直在玩的一些代码:
#include <cassert>
// Some forward declarations:
enum class literal_id;
struct literal_base;
struct literal_a;
struct literal_b;
// Now some definitions:
enum class literal_id {
a, b
};
struct literal_base {
virtual literal_id method() const noexcept = 0;
};
struct literal_a : public literal_base {
constexpr literal_id method() const noexcept final { return literal_id::a; }
constexpr operator literal_b() const noexcept;
};
struct literal_b : public literal_base {
constexpr literal_id method() const noexcept final { return literal_id::b; }
constexpr operator literal_a() const noexcept;
};
constexpr literal_a::operator literal_b() const noexcept { return literal_b(); }
constexpr literal_b::operator literal_a() const noexcept { return literal_a(); }
// Some test methods
literal_id process_literal_base(literal_base const& l) { return l.method(); }
constexpr literal_id process_literal_a(literal_a const& l) { return l.method(); }
constexpr literal_id process_literal_b(literal_b const& l) { return l.method(); }
// Some test variables
constexpr auto a = literal_a();
constexpr auto b = literal_b();
int main() {
// Compile-time tests, all ok
static_assert(process_literal_a(b) == literal_id::a, "");
static_assert(process_literal_b(a) == literal_id::b, "");
// Runtime tests, all ok
assert(process_literal_base(a) == literal_id::a);
assert(process_literal_base(b) == literal_id::b);
return 0;
}
一些言论:
- 我有一个带有隐式(且因此琐碎)驱动器的基类
literal_base
,因为它的子类别都不应该有一个琐碎的破坏者,但它们是字面类型的类型。 -
literal_base
具有用于测试的单个method
功能,但目的是使其具有尽可能多的纯虚拟函数(非虚拟最终功能也有效)。
)。
- 请注意,即使不是标记
virtual
,method
覆盖子类中的覆盖也为final
。这只是为了使编译器保持沉默,因为这些类应该是叶子(在其继承树中)或没有覆盖功能。(所有这些都与pre-c 11未定义的行为语义有关,以最终实现虚拟函数,而final
指定尚不存在。) - 创建了
process_*
功能是为了帮助断言在编译和运行时实现的正确性。 - 我也无缘无故地演奏了价值语义,一切都很好:)
字面类型的一些相关定义:
... 可能具有以下所有属性的CV合格类类型:
- (1)有一个微不足道的破坏者。 [[他们有(我的意思是
literal_base
的子类)]- (2)是
- (2.1)聚合类型, [[不适用]]
- (2.2)一种至少一个constexpr(可能是模板)构造函数的类型,它不是副本或移动构造函数, [[它具有,但仅仅是因为所有类都没有明确的构造函数;但是很容易实现]
- (2.3)闭合类型(自C 17) [[[不适用]]
- (3)对于工会,至少一个非静态数据成员是非易失性文字类型, [[[不适用]]
- (4)对于非工会,所有非静态数据成员和基类都是非挥发性的字面类型。(因为C 17) [[示例中没有
volatile
,并且在真实应用程序中都不得使用volatile
;另外,literal_base
的子类应该是字面类型,因此该规则必须(并且可以)应用]]- (5)所有非静态数据成员和基类都是非易失性字面类型的。 [[基本上]]
现在constexpr函数的一些定义:
- 一定不能是虚拟 [[[没有一个子类具有虚拟函数;所有这些都是最终的,因此他们的位置是知道的,而无需例如vtables]]
- (...)
我可以承担所有这些吗?我忽略的规范有什么吗?
[dcl.constexpr]中的规则很清楚:
constexpr
功能的定义应满足以下要求:
- 它不会是虚拟的(10.3);
literal_a::method
和literal_b::method
都是virtual
,因为每个literal_base::method
均为virtual
。因此,它们不能是constexpr.
,它们是final
并不重要。该程序的形式不佳。
IT 是是,允许文字类型具有virtual
成员函数。