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

履歴 編集

コンパイル時アサート(C++11)

概要

static_assert宣言は、指定した定数式が真であることを表明するための機能である。

これは、コンパイル時に満たされるべき要件を検証するために使用できる。

template <class T, std::size_t N>
struct X {
  static_assert(N > 0, "number of array elements must greater than 0");
  T array[N];
};

指定した定数式が偽である場合はコンパイルエラーとなり、static_assertの第2引数で指定した文字列リテラルが診断メッセージとして出力される。

仕様

static_assert宣言は、以下の形式を持つ:

static_assert(定数式, 文字列リテラル);

  • 定数式は、boolに変換可能な整数定数式であること
  • この宣言は、名前空間スコープ、ブロックスコープ、メンバ宣言といった場所で記述できる
  • 定数式が真であると評価された場合は何も効果がない。定数式が偽であると評価された場合は、指定された文字列リテラルを含む診断メッセージがコンパイラによって問題報告される。ただし、基本ソース文字集合に含まれない文字集合は、診断メッセージに表示することはコンパイラに要求されない
  • static_assert宣言では、新たな型やオブジェクトは宣言しない。また、実行時にサイズや時間コストは発生しない
  • (CWG 2518が適用された環境): template文(もしくは適切な特殊化やC++17 constexpr if 文の中の文)が実際にインスタンス化されるまで、static_assert文の宣言は遅延される。
  • C++17 constexpr if 文の解説を参照

#include <type_traits>

template <class T>
struct X {
  static_assert(std::is_integral<T>::value, "template parameter T must be integral type");

  // …
};

int main()
{
  X<int>(); // OK
//X<double>(); // コンパイルエラー : template parameter T must be integral type
}

出力

この機能が必要になった背景・経緯

標準C++にはこれまで、ソフトウェアの正しさを表明するための機能として、

  • 実行時のassertマクロ
  • プリプロセス時の#errorディレクティブ

この2つがあった。テンプレートライブラリを作るにあたって、これらはテンプレート引数のアサーションには使用できなかった。

この問題を解決する必要性は、Boost Static Assertion Libraryと、それを利用する他のBoostライブラリの存在によって示されている。Boostには含まれていないLokiライブラリにもSTATIC_CHECKというマクロの形で同様の機能がある。CzarneckiとEiseneckerによる著書『Generative Programming (邦訳 : ジェネレーティブプログラミング)』では、コンパイル時アサートをシミュレートするためにテンプレートメタプログラミング手法を使用し、コンフィグレーションを生成する中間段階でのチェックを行っている。

Boost Static Assertion Libraryが開発されたときに、コンパイル時アサートの設計要件が認識された:

  • アサーションに関する全ての処理は、コンパイル時に実行する必要がある。実行時に空間的、時間的なコストをかけることは許可しない
  • 初心者に教えることが容易な構文を持つ必要がある
  • アサーションの失敗には、意味がわかり(meaningful)、十分な情報がある(informative)診断メッセージが必要である
  • それは名前空間、クラス、ブロックスコープで使用できること
  • この機能の誤用によって静かに故障したりはせず、誤用もまたコンパイル時に診断される

今回導入された機能は、これら全ての要件を満たす。

コンパイル時アサートのためにBOOST_STATIC_ASSERTSTATIC_CHECKのようなマクロを使用することは、名前空間を汚染する問題があるが、コア言語にその機能を追加することでその問題は解消される。

関連項目

参照