这个constexpr虚函数技术是否违反了任何C++ 11/C++ 14规则?

Flá*_*bôa 7 c++ virtual-functions constexpr c++11 c++14

前几天我正在阅读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;
}
Run Code Online (Sandbox Code Playgroud)

一些评论:

  • 我有一个literal_base带有隐式(因此是微不足道的)析构函数的基类,因为它的子类都不应该只有一个简单的析构函数 - 毕竟它们是文字类型.
  • literal_base具有method用于测试的单个函数,但其​​目的是使其具有所需数量的纯虚函数(非虚函数最终函数也有效).
  • 请注意,即使未标记method子类,也会标记子类中的替代.这只是为了使编译器静音,因为这些类应该是leaf(在它们的继承树中)或没有覆盖的函数.(所有这些都与pre-C++ 11未定义的行为语义有关,用于虚函数的最终实现,当说明符尚不存在时.)finalvirtualfinal
  • process_*创建这些函数是为了帮助在编译和运行时声明实现的正确性.
  • 我也玩了价值语义,没有任何理由,一切都很好:)

文字类型的一些相关定义:

...可能具有以下所有属性的cv限定类类型:

  • (1)有一个简单的析构函数.[[他们有(literal_base我的意思是子类)]]
  • (2)是
    • (2.1)聚合类型,[[不适用]]
    • (2.2)一个至少有一个constexpr(可能是模板)构造函数的类型,它不是一个复制或移动构造函数,[[它有,但只是因为没有一个类有一个显式的构造函数; 但它很容易实现]]
    • (2.3)闭包类型(自C++ 17起)[[不适用]]
  • (3)对于工会,至少有一个非静态数据成员属于非易失性文字类型,[[不适用]]
  • (4)对于非联合,所有非静态数据成员和基类都是非易失性文字类型.(因为C++ 17)[[ volatile在示例中没有,并且都不应该volatile在实际应用程序中使用; 另外,literal_base子类应该是文字类型,因此必须(并且可以)应用此规则]]
  • (5)所有非静态数据成员和基类都是非易失性文字类型.[[基本上如[4]]]

现在有一些constexpr函数的定义:

  • 它不能是虚[[没有子类有虚函数; 所有这些都是最终的,因此他们的位置是已知的,无需例如vtable]]
  • (......)

我是否正确地承担这一切?有什么关于我忽略的规格吗?

Bar*_*rry 10

[dcl.constexpr]中的规则非常明确:

constexpr功能的定义应满足以下要求:
- 不应是虚拟的(10.3);

literal_a::method并且literal_b::method都是virtual因为他们每个都覆盖literal_base::method,这是virtual.因此,它们不可能是constexpr.它们无关紧要final.该计划格式不正确.

一个文本类型允许有一个真正的virtual成员函数虽然.

  • 自 C++20 起与此无关。 (4认同)