15

通常、constexpr には副作用があってはなりません。ただし、スローされた例外のコンストラクターで副作用を使用できることを発見しました。この手法は、次のプログラムで示されているように、constexpr 関数の assert() をエミュレートするために使用できます。

#include <iostream>
#include <cstdlib>
#include <stdexcept>

struct constexpr_precond_violated : std::logic_error
{
  constexpr_precond_violated(const char* msg) :
    std::logic_error(msg)
  {
    std::cerr << msg << '\n';
    abort(); // to get a core dump
  }
};

#define TO_STRING_IMPL(x) #x
#define TO_STRING(x) TO_STRING_IMPL(x)

#define CONSTEXPR_PRECOND(cond, value) \
  ((!(cond)) ? throw constexpr_precond_violated( \
    "assertion: <" #cond "> failed (file: " \
    __FILE__ ", line: " TO_STRING(__LINE__) ")")    \
   : (value))

constexpr int divide(int x, int y)
{
  return CONSTEXPR_PRECOND(y != 0, x / y);
}

int main(int argc, char** argv)
{
  // The compiler cannot know argc, so it must be evaluated at runtime.
  // If argc is 2, the precondition is violated.
  return divide(100, argc - 2);
}

g++ 4.7.2 と clang++ 3.1 でテストしました。前提条件が失敗すると、エラーの場所とコア ダンプが取得されます。

./constexpr_assert some_arg
assertion: <y != 0> failed (file: constexpr_assert.cpp, line: 26)
Aborted (core dumped)

現在のコンパイラで動作しますが、合法的な C++11 ですか?

4

1 に答える 1

14

合法です。

constexpr関数には、定数式になるいくつかの引数値が必要です (§7.1.5/5):

関数の場合、constexpr関数呼び出し置換が定数式 (5.19) を生成するような関数引数値が存在しない場合、プログラムは不正な形式です。診断は必要ありません。

これは、考えられるすべての引数値が定数式になる必要があるという意味ではないことに注意してください。divideには、明らかに定数式になるいくつかの引数値があります:divide(1, 1)は単純な例です。したがって、定義は明らかに有効です。

しかしdivide(1, 0)、呼び出すことができますか?はい、できます。constexpr関数の呼び出しと「通常の」関数の呼び出しにほとんど違いはありません(§7.1.5/7):

関数への呼び出しは、関数への呼び出しが定数式に現れる可能性があることを除いて、すべての点でconstexpr同等の非関数への呼び出しと同じ結果を生成します。constexprconstexpr

constexpr関数への呼び出しは定数式で使用できますが、結果が定数式にならないようにすることは何も禁止されていないことに注意してください。constexprこれは、コンパイル時引数と実行時引数の両方で関数を呼び出せるようにすることを目的としています (そうしないと、 の有用性constexprがいくつか制限されます)。

完全を期すために、定数式を構成するものを見てみましょう (§5.19/2):

条件式は、潜在的に評価される部分式 (§3.2) として次のいずれかが含まれていない限り、コア定数式ですが、論理 AND (§5.14)、論理 OR (§5.15)、および条件付き (§5.16) 操作の部分式です。評価されないものは考慮されません [...]。

divide(1, 1)は定数式ですが、そうではdivide(1, 0)ありません。divide(1, 0)テンプレート パラメータで使用すると、プログラムの形式が正しくなくなります。しかし、それ以外は問題ありません。

于 2012-10-23T21:58:17.330 に答える