この些細な例では、_test2
_が成功したとしても_test1
_はコンパイルに失敗し、なぜそうなのかわかりません。 _arr[i]
_がconstexpr
とマークされた関数からの戻り値に適している場合、それを非型テンプレート引数として使用できないのはなぜですか?
_template<char c>
struct t
{
static const char value = c;
};
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i)
{
return arr[i];
}
template <unsigned N>
constexpr char test2(const char (&arr)[N], unsigned i)
{
return t<arr[i]>::value;
}
int main()
{
char a = test1("Test", 0); //Compiles OK
char b = test2("Test", 0); //error: non-type template argument
//is not a constant expression
}
_
編集:これは違いはありません:
_template<char c>
struct t
{
static const char value = c;
};
template <unsigned N>
constexpr char test1(const char (&arr)[N])
{
return arr[0];
}
template <unsigned N>
constexpr char test2(const char (&arr)[N])
{
return t<arr[0]>::value;
}
int main()
{
char a = test1("Test"); //Compiles OK
char b = test2("Test"); //error: non-type template argument
//is not a constant expression
}
_
簡単な答え:_C++11/14
_にはconstexpr
関数パラメーターはありません。
より長い答え:test1()
では、i
がコンパイル時定数でない場合、関数は実行時にまだ使用可能です。しかし、test2()
では、i
がコンパイル時定数であるかどうかをコンパイラーに認識できませんが、関数をコンパイルするために必要です。
例えば。 _test1
_の次のコードはコンパイルされます
_int i = 0;
char a = test1("Test", i); // OK, runtime invocation of test1()
constexpr int i = 0;
constexpr char a = test1("Test", i); // also OK, compile time invocation of test1()
_
あなたのtest2()
を単純に
_constexpr char test3(unsigned i)
{
return t<i>::value;
}
_
test3(0)
の内部では、i
が無条件コンパイル時の式であることを証明できないため、これはtest3()
に対してコンパイルされません。それを表現するには、constexpr
関数パラメーターが必要です。
5.19定数式[expr.const]
2条件式eは、抽象マシン(1.9)の規則に従ってeの評価が以下の式のいずれかを評価しない限り、コア定数式です。
—参照に先行する初期化と次のいずれかがない限り、参照型の変数またはデータメンバーを参照するid-expression
—定数式または— eの評価内で有効期間が開始されたオブジェクトの非静的データメンバーです。
このセクションには、質問に対応する次のコード例があります。
_constexpr int f1(int k) {
constexpr int x = k; // error: x is not initialized by a
// constant expression because lifetime of k
// began outside the initializer of x
return x;
}
_
上記の例のx
は定数式ではないため、_f1
_内でx
またはk
のいずれかを使用してテンプレートをインスタンス化できないことを意味します。
ここでconstexpr
が何をするかについての誤解があります。関数はコンパイル時に適切な引数に対して評価可能でなければならないことを示しますが、一般的なケースではまだコンパイルするための要件をnot削除します。
最初のバージョンを見てみましょう:
template <unsigned N>
constexpr char test1(const char (&arr)[N], unsigned i) {
return arr[i];
}
さて、これは明らかにコンパイル時の評価です:
enum { CompileTimeConstant = test1("Test", 0) };
あなたの例may beですが、オプティマイザー/ QoIの問題です:
char MayBeCompileTimeConstant = test1("Test", 0);
この例は明らかにそうではありませんが、まだ評価可能である必要があります
char arr[10];
int i;
std::cin >> i;
std::cin >> arr;
char b = test1(arr, i);
std::cout << "'" << arr << "'[" << i << "] = " << b << '\n';
test2
は、最後のケースではおそらくコンパイルできません。まったくコンパイルできません。 (コードがgoodであることを示唆していないことに注意してください)。
ここでの問題は、arr[i]
は添字演算子を呼び起こしますoperator[]
。 この演算子は定数式を返しません。
それは実際にconstexpr
の問題ではなく、テンプレート引数の推論の問題です。非型テンプレート引数は、添字演算子の戻り引数ではない定数式でなければなりません。
したがって、コンパイラはarr[i]
は定数式ではありません。
なぜならarr[i]
はコンパイル時の定数式ではありません。実行時に異なる場合があります。