yohhoyの日記

技術的メモをしていきたい日記

static_assert(false, "was wrong");

プログラミング言語C++におけるconstexpr if文とstatic_assert宣言の組合せに関するメモ。

2023年2月会合にてstatic_assert(false)を許容するP2593R1CWG 2518へと統合され*1C++言語仕様に対するDefect Reportとして遡及適用される。*2

CWG 2518適用前のC++言語仕様では、下記コードはプログラマの意図に反して関数テンプレートのインスタンス化より前にコンパイルエラーとなる。

#include <type_traits>

template <typename T>
T doubling(T x)
{
  if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
    // 算術型の場合は2倍した値を返す
    return x * T{2};
  } else {
    // それ以外の型はコンパイルエラー
    static_assert(false);  // NG(CWG 2518適用前)
    // CWG 2518適用後は上記記述でOK
  }
}

CWG 2518未適用C++コンパイラに対する回避策としては、static_assert宣言に「テンプレートパラメータに依存する(depends)が常にfalseを返す」ヘルパ変数always_false_v<T>などを経由した条件式を指定する。

#include <type_traits>

template <typename T>
constexpr bool always_false_v = false;

template <typename T>
T doubling(T x)
{
  if constexpr (std::is_integral_v<T> || std::is_floating_point_v<T>) {
    // 算術型の場合は2倍した値を返す
    return x * T{2};
  } else {
    // それ以外の型はコンパイルエラー
    static_assert(always_false_v<T>);  // OK
  }
}

CWG 2518適用により、static_assert宣言の評価がインスタンス化タイミングに遅延される。オリジナルの提案文書P2593R1 §3.1より一部引用(下線部は強調)。

This sidesteps the question of whether it’s just static_assert(false) that should be okay or static_assert(0) or static_assert(1 - 1) or static_assert(not_quite_dependent_false). anything else. Just, all static_assert declarations should be delayed until the template (or appropriate specialization or constexpr if substatement thereof) is actually instantiated.

If the condition is false, we’re going to get a compiler error anyway. And that’s fine! But let’s just actually fail the program when it’s actually broken, and not early.

P2593R1 Allowing static_assert(false)

関連URL