最終更新日時(UTC):
が更新

履歴 編集

定数式でのvoid*からポインタ型へのキャストを許可 [P2738R1](C++26)

このページはC++26に採用される見込みの言語機能の変更を解説しています。

のちのC++規格でさらに変更される場合があるため関連項目を参照してください。

概要

C++23までは、定数式の文脈でのvoid*から元のポインタ型への変換が禁止されていたが、C++26からは許可される。

void*から元のポインタ型への変換は、「型消去 (type erasure)」で有用に使われるもので、標準ライブラリの実装としてはstd::anystd::function_refstd::format()などで使われており、これらがコンパイル時に使用できるようにするための必要となる。

型消去は、テンプレートインスタンスの数を減らし、バイナリサイズを小さくするために一般的に使用される技法である。とくに、メモリ制約のある組み込みプラットフォームでは、共通のコードパスを確保するために型消去が有効である。

void*から元のポインタ型に変換することによる型消去の例としては、以下のようになる:

#include <string_view>

struct Sheep {
  constexpr std::string_view speak() const noexcept { return "Baaaaaa"; }
};
struct Cow {
  constexpr std::string_view speak() const noexcept { return "Mooo"; }
};

class AnimalView {
private:
  const void* animal;
  std::string_view (*speak_function)(const void*);
public:
  template <typename Animal>
  constexpr AnimalView(const Animal &a)
    : animal{&a}, speak_function{[](const void* object) {
        return static_cast<const Animal*>(object)->speak();
      }}
  {}

  constexpr std::string_view speak() const noexcept {
    return speak_function(animal);
  }
};

int main() {
  constexpr Cow cow;
  constexpr AnimalView av{cow};
  constexpr auto result = av.speak();
}

仕様

定数式として許可されない操作を、以下のように変更:

  • 変更前:「(CV修飾) void* 型からオブジェクトへのポインタ型への変換」
  • 変更後:「(CV修飾) void へのポインタ型のprvalue (一時オブジェクト) P から、オブジェクトへのポインタ型Tへの変換。ただし、PTと類似 (similar) の型のオブジェクトを指している場合を除く」

これはつまり、Tからvoid*を経由してTに変換することは許可されるが、void*を経由してほかの型に変換することは禁止されたままとなる。

関連項目

参照