私はC++ 17標準で遊んでみました。 C++ 17 if constexpr
の機能の1つを使おうとしました。そして、私は問題を抱えていました...次のコードを見てください。これはエラーなしでコンパイルされます。次のコードでは、if constexpr
を使用してそれがポインターであるかどうかを確認しようとしました。
#include <iostream>
#include <type_traits>
template <typename T>
void print(T value)
{
if constexpr (std::is_pointer_v<decltype(value)>)
std::cout << "Ptr to " << *value << std::endl; // Ok
else
std::cout << "Ref to " << value << std::endl;
}
int main()
{
auto n = 1000;
print(n);
print(&n);
}
しかし、以下に示すように、上記のコードを書き直すと、if constexpr
はmain
関数に含まれます。
#include <iostream>
#include <type_traits>
int main()
{
auto value = 100;
if constexpr (std::is_pointer_v<decltype(value)>)
std::cout << "Ptr to " << *value << std::endl; // Error
else
std::cout << "Ref to " << value << std::endl;
}
コンパイルエラーが発生します:
main.cpp:8:32: error: invalid type argument of unary ‘*’ (have ‘int’) std::cout << "Ptr to " << *value << std::endl;
問題は主な機能にはありません。これは、次のような任意の関数にすることができます。
void print()
{
auto value = 100;
if constexpr (std::is_pointer_v<decltype(value)>)
std::cout << "Ptr to " << *value << std::endl; // Error
else
std::cout << "Ref to " << value << std::endl;
}
int main()
{
print();
}
型が入力パラメーターからdecltypeによって推定されたとしても、なぜif constexpr
がテンプレート関数でのみ機能するのか知りたいのですが。
入力パラメーターから
decltype
によって型が推定されたとしても、「if constexpr
」がテンプレート関数でのみ機能する理由を知りたいのですが。
これは仕様によるものです。
if constexpr
はインスタンス化分岐はテンプレート内にある場合は取得されません。トークンスープとして扱われないブランチを処理するだけでなく、それを解析したり、セマンティック分析を完全に実行したりすることを回避します。どちらの側もまだ分析されており、*value
はint
sに対して不正な形式であるため、エラーになります。
テンプレート以外のコードのコンパイルを回避するためにif constexpr
を使用することはできません。特定の専門分野では無効になる可能性のあるテンプレートコードのインスタンス化を回避するだけです。
C++標準、9.4.1節:
Ifステートメントがifconstexprの形式である場合、条件の値は、ブール型(8.6)のコンテキスト変換された定数式でなければなりません。この形式は、constexprifステートメントと呼ばれます。変換された条件の値がfalseの場合、最初のサブステートメントは破棄されたステートメントです。それ以外の場合、2番目のサブステートメントが存在する場合は破棄されたステートメントです。 囲んでいるテンプレートエンティティのインスタンス化中に(第17節)、インスタンス化後に条件が値に依存しない場合、破棄されたサブステートメント(存在する場合)はインスタンス化されません。
(私の強調)
したがって、constexpr if
のサブステートメントは、テンプレート内にない場合でもインスタンス化されるため、少なくともコンパイルする必要があります。