このページはC++26に採用される見込みの言語機能の変更を解説しています。
のちのC++規格でさらに変更される場合があるため関連項目を参照してください。
概要
C++26では、constexprの文脈で仮想継承が許可される。
これまで、constexprコンストラクタおよびデストラクタを持つクラスは仮想基底クラスを持つことができなかった。C++26ではこの制限が撤廃され、仮想継承を含むクラス階層でもコンパイル時の定数評価が可能になる。
struct Base {
constexpr virtual ~Base() = default;
};
struct Derived : virtual Base {
constexpr Derived() = default; // C++26: OK (C++23以前: 不適格)
constexpr ~Derived() = default; // C++26: OK (C++23以前: 不適格)
};
constexpr Derived d{}; // OK
仕様
constexpr宣言の仕様にあった以下の制約が削除される:
- (
constexpr指定された対象が) コンストラクタまたはデストラクタである場合、そのクラスは仮想基底クラスを持たないこと
これにより、仮想基底クラスを持つクラスのコンストラクタおよびデストラクタにconstexprを指定できるようになる。
例
#include <cassert>
struct Common {
unsigned counter{0};
constexpr virtual ~Common() = default;
};
struct Left : virtual Common {
constexpr const unsigned& get_counter() const {
return counter;
}
};
struct Right : virtual Common {
constexpr const unsigned& get_counter() const {
return counter;
}
};
struct Child : Left, Right {};
int main() {
constexpr auto ch = Child{};
// 菱形継承でも仮想基底クラスのメンバは共有される
static_assert(&ch.Left::get_counter() == &ch.Right::get_counter());
}
出力
この機能が必要になった背景・経緯
C++のconstexpr機能は段階的に拡張されてきたが、仮想継承を含むクラスのコンストラクタ・デストラクタをconstexprにすることは禁止されたままだった。これはconstexprの文脈で許可されない最後の構文上の制限であった。
この制限は、標準ライブラリのconstexpr化を妨げる障害にもなっていた。特に、std::stringstreamなどのストリームユーティリティは仮想継承を使用しており、この制限によりコンパイル時に使用できなかった。また、<chrono>の例外型(chrono::nonexistent_local_timeなど)のconstexpr化も阻害されていた。