9
#include <exception>

constexpr bool foo(bool x)
{
  return x ? true : throw std::exception();
}

int main()
{
  // 1) must never be compiled
  // static_assert(foo(false), "");

  // 2) must always be compiled?
  const bool x = foo(false);

  // 3) must never compile?
  constexpr bool y = foo(false);

  return 0;
}

(1) はコンパイル エラーにつながるに違いないと確信しています。(2) は実行時に失敗しますが、コンパイル時に拒否されてはならないことは確かです。

興味深いケースは constexpr 変数 (3) です。この単純な例では、gcc と clang は実際に式を評価するため、プログラムを拒否します。(エラー メッセージ: y は定数式ではありません)。

すべての C++11 コンパイラーはプログラムを拒否することを余儀なくされていますか? foo(false) をより複雑な式に置き換えたらどうなるでしょうか?

constexpr がチューリング完全ではないことを知って驚きましたが、これは仕様の変更後になります 。constexpr ベースの計算はチューリング完全ですか?

多分これは私の質問に関連しています。私の知る限り、コンパイラは、この例の constexpr (3) の実際の評価を実行時まで延期することが許可されています。しかし、constexpr がチューリング完全である場合、コンパイラがすべての constexpr に対して例外をスローするかどうか (つまり、constexpr が無効であることを意味します) を決定できるとは信じがたいと思います。

4

2 に答える 2

8

私の読みでは、はい、すべてのコンパイラはステートメント (3) について不平を言う必要があります。

N3242 7.1.5 パラグラフ 9:

constexprオブジェクト宣言で使用される指定子は、オブジェクトを として宣言しますconst。そのようなオブジェクトはリテラル型を持ち、初期化されます。コンストラクター呼び出しによって初期化された場合、その呼び出しは定数式 (5.19) でなければなりません。それ以外の場合、初期化子に現れるすべての完全式は定数式になります。初期化式の変換に使用される各暗黙的な変換と、初期化に使用される各コンストラクター呼び出しは、定数式 (5.19) で許可されているもののうちの 1 つでなければなりません。

constexprオブジェクトは「コンパイル時に評価される」と考え、constexpr関数またはconstexprコンストラクターは「コンパイル時に評価される可能性がある」と考えています。コンパイラは、コンパイル時に (3) のようなステートメントの意味の妥当性を判断する必要があります。「評価」は実行時に実行できると主張することもできますが、有効性のチェックはとにかくそのほとんどの作業を行います。さらに、コードは のようなテンプレートをインスタンス化し続けることができます。これにより、コンパイラがコンパイル時にCheck<y>の値を把握する必要があることがほぼ保証されます。y

これは、コンパイラに非常に長い、または無限の時間がかかるようにする悪魔的なプログラムを作成できることを意味します。operator->しかし、それはトリックですでに可能だったと思います。

于 2012-10-27T21:49:55.503 に答える
5

(1) はコンパイル エラーにつながるに違いないと確信しています。(2) は実行時に失敗しますが、コンパイル時に拒否されてはならないことは確かです。

正しい。条件演算子のthrow部分は定数式ではなく、(1)では未評価ではありません。(2) の場合、fooコンパイル時に強制的に評価されることはありません。

(3) の場合、コンパイラはどのようにして評価を後回しにすることができますか? constexprdecl-specifierは、コンパイル時に評価されることを強制します。 foo基本的には(1)と同じですが、の初期化はy定数式が必要なコンテキストです。

§7.1.6 [dcl.constexpr] p9

constexprオブジェクト宣言で使用される指定子は、オブジェクトを として宣言しますconst。そのようなオブジェクトはリテラル型を持ち、初期化されます。コンストラクター呼び出しによって初期化される場合、その呼び出しは定数式 (5.19) でなければなりません。それ以外の場合、またはconstexpr指定子が参照宣言で使用されている場合、その初期化子に現れるすべての完全式は定数式になります。[...]

于 2012-10-27T21:51:54.910 に答える