web-dev-qa-db-ja.com

C ++ 17の「Ifconstexpr」はテンプレート化されていない関数では機能しません

私は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 constexprmain関数に含まれます。

#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がテンプレート関数でのみ機能するのか知りたいのですが。

19
NYM

入力パラメーターからdecltypeによって型が推定されたとしても、「if constexpr」がテンプレート関数でのみ機能する理由を知りたいのですが。

これは仕様によるものです。

if constexprインスタンス化分岐はテンプレート内にある場合は取得されません。トークンスープとして扱われないブランチを処理するだけでなく、それを解析したり、セマンティック分析を完全に実行したりすることを回避します。どちらの側もまだ分析されており、*valueintsに対して不正な形式であるため、エラーになります。

テンプレート以外のコードのコンパイルを回避するためにif constexprを使用することはできません。特定の専門分野では無効になる可能性のあるテンプレートコードのインスタンス化を回避するだけです。

22
Barry

C++標準、9.4.1節:

Ifステートメントがifconstexprの形式である場合、条件の値は、ブール型(8.6)のコンテキスト変換された定数式でなければなりません。この形式は、constexprifステートメントと呼ばれます。変換された条件の値がfalseの場合、最初のサブステートメントは破棄されたステートメントです。それ以外の場合、2番目のサブステートメントが存在する場合は破棄されたステートメントです。 囲んでいるテンプレートエンティティのインスタンス化中に(第17節)、インスタンス化後に条件が値に依存しない場合、破棄されたサブステートメント(存在する場合)はインスタンス化されません。

(私の強調)

したがって、constexpr ifのサブステートメントは、テンプレート内にない場合でもインスタンス化されるため、少なくともコンパイルする必要があります。

8
lisyarus