web-dev-qa-db-ja.com

constexpr関数では何が許可されますか?

constexpr functions には以下が含まれていません:

非リテラル型の変数の定義

しかし、この回答ではラムダは1つで定義されています: https://stackoverflow.com/a/41616651/2642059

template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    return [&]() {
        decltype(std::div(quot, rem)) result;
        result.quot = quot;
        result.rem = rem;
        return result;
    }();
}

私のコメントでは、div_tを1つに定義しています: div_tオブジェクトを初期化するにはどうすればよいですか?

template <typename T>
constexpr decltype(div(T{}, T{})) make_div(const T quot, const T rem)
{
    decltype(div(T{}, T{})) x{};
    x.quot = quot;
    x.rem = rem;
    return x;
}

「非リテラル型の変数の定義」の禁止は、正確にはどういう意味ですか?

Visual Studio 2015ではdiv_tの定義を許可していませんが、そのような不正な動作をラムダでラップして実行することは許容されているので、無意味だと思います。どちらかのコンパイラがdiv_tの定義に関して正しく動作しているかどうかを知りたいのですが。

17
Jonathan Mee

Visual Studio 2015は c ++ 14 の拡張子constexprhttps: //msdn.Microsoft.com/en-us/library/hh567368.aspx#C-14-Core-Language-Features

C++ 11 constexpr関数

関数の本文にはのみを含めることができます。

  • nullステートメント(プレーンセミコロン)
  • _static_assert_宣言
  • クラスまたは列挙を定義しないtypedef宣言およびエイリアス宣言
  • using宣言
  • usingディレクティブ
  • 正確に1つのreturnステートメント

したがって c ++ 11decltype(div(T{}, T{})) x{}の定義を許容できません。ただし、同じ結果を得るには、constexpr関数で推奨される3項 here をロールしてもかまいません。

_template <typename T>
constexpr auto make_div(const T quot, const T rem)
{
    using foo = decltype(div(T{}, T{}));

    return foo{1, 0}.quot != 0 ? foo{quot, rem} : foo{rem, quot};
}
_

Live Example

C++ 14 constexpr関数

関数本体には、以外のものが含まれる場合があります

  • asm宣言
  • gotoステートメント
  • caseおよびdefault以外のラベルを持つステートメント
  • トライブロック
  • 非リテラル型の変数の定義
  • 静的またはスレッドストレージ期間の変数の定義
  • 初期化が実行されない変数の定義

"リテラルタイプ"が定義されている場合 ここ 、特にオブジェクトの場合は、それらは自明なデストラクタを持つ集約タイプである可能性があります。したがって、_div_t_は間違いなく適格です。したがって c ++ 14 、および拡張gccにより、decltype(div(T{}, T{})) x{}の定義を許容できます。

C++ 17 constexpr関数

C++ 17では、「リテラルタイプ」の定義にクロージャタイプのサポートが追加されたため、gccとVisual Studioの両方がreturnステートメントでのラムダの使用をサポートしているのは奇妙です。それは前向きなサポートか、コンパイラがラムダをインライン化することを選択したかのどちらかだと思います。どちらの場合でも、 c ++ 14constexpr関数としての資格があるとは思いません。

[ ソース ]

16
Jonathan Mee