4

@cyberpunk_は何かを達成しようとしていて、それについていくつか質問をしましたが、すべての追跡はこれに要約されます。

関数のコンパイル時評価を強制するツールを構築することは可能constexprですか?

int f(int i) {return i;}
constexpr int g(int i) {return i;}

int main()
{
    f(at_compilation(g, 0));
    int x = at_compilation(g, 1);
    constexpr int y = at_compilation(g, 2);
}

どのような状況でも、at_compilationのコンパイル時の評価を強制しgます。

at_compilationこの形である必要はありません。

要件

  • constexpr 関数の入力として任意の (数値ネイティブ) リテラル型を許可します。
    • これは、関数の引数の型に基づいてハードコーディングすることもできます。
  • constexpr 関数呼び出しの結果である任意の (数値ネイティブ) リテラル型を出力として許可します。
    • これは、関数の戻り値の型に基づいてハードコーディングすることもできます。

望ましいもの

  • マクロの使用を減らしましたが、使用することを恐れないでください。
  • 一般的であること (ハードコーディングされていない型)。
  • あらゆるリテラル型をサポートします。最後に、数値のネイティブ リテラル型は必須です。

関連する質問:

  1. コンパイル時に constexpr 関数が評価されるのはいつですか?
  2. コンパイル時に定数式を強制的に評価しますか?
  3. テンプレートパラメーターとして関数を渡しますか?
  4. C++11 標準のどこで、変換中に constexpr 関数をいつ評価できるかを指定していますか?

関連するコード サンプルによる回答:

  • 1
  • 2
  • 3 (これには説明AT_COMPILATIONマクロがあります)

すべてのコード サンプルには、要件に関する制限があります。

これが C++ ではどのように実行不可能であるかについての明確な説明も良い答えです。

@K-ballo / @Herb Sutter の「結果は定数式でも使用される」という回答に基づいて、それは不可能だと思います。これは、関数に関する私の以前の概念の一部ではありませんでしたconstexpr。最初は、リテラル (またはその他のコンパイル時の入力) を引数として渡すだけで、(標準で) コンパイル時に評価されることを保証するのに十分であると考えました。

constexpr 関数の目的は、配列境界のように、必要に応じて定数式の状況に適合できることであると既に想定されています。それで大丈夫です。それを考えると、この質問は、コンパイル時間の計算のためのツールとしてそれらを使用することに関するハックに関するものです。それが良いことか悪いことかは問題ではありません。

4

3 に答える 3

3

コンパイラはコンパイル時に使用される値を計算する必要があるだけであり、クラス型の値のすべての部分を使用できる一般的な式がないため、それは不可能だと思います。プライベート メンバーを初期化する計算は、結果を使用するためにパブリック constexpr メンバー関数に依存するため、強制することさえ不可能な場合があります。

オブジェクト表現にアクセスできる場合

static_cast< char const * >( static_cast< void const * >( & const_value ) )

次に、計算の結果をチェックサムし (そしてその結果を整数定数式として使用し)、意味のないすべての計算をコンパイラに強制的に実行させることができます。void *しかし、 toからのキャストchar *は定数式では許可されておらず、同様に a で同じことを達成しようとしていunionます。許可されていたとしても、コンストラクターが 1 バイトを初期化せずに残した場合、初期化されていない値を定数式で使用することも禁止されます。

そのため、たとえ C++ にイントロスペクションのためのより優れたツールがあったとしても、一部のメンバーを人為的に使用し、他のメンバーを使用しないために constexpr 関数によって実行された作業を回復することは依然として不可能です。

明確にするために(質問が繰り返されたとしても)、これが必要な理由はありません。この言語では、必要に応じて、コンパイル時にすべてを計算できることを確認する必要があります。また、純粋な値を遅延なく計算するようにコンパイラに強制する唯一の効果は、速度が遅くなり、より多くのメモリを使用することです。

編集(質問は根本的に変更されました)

スカラー型を返す関数がいくつかあり、そのうちのいくつかが特定の引数の下で定数式として機能することを確認したい場合は、 を使用してテスト ケースを記述しstatic_assertます。

constexpr int g(int i) {return i;}
int i = 5;
static_assert( g( 3 ) == 0, "failure 1" );
static_assert( g( i ) == 5, "failure 2" );

結果の値を修正したくない場合は、破棄してください。(残念ながら、GCCはそのような式の非定数部分を最適化する可能性があるため、そのプラットフォームではもっとバロック的なことをする必要があるかもしれません。

static_assert( g( i ) == 5 || true, "failure only if not constexpr" );

これをマクロにカプセル化することに関しては、他のリンクされた質問が多くのことに対処しているようです。これらの回答のいずれかを拡張したり、特定のバグを修正したい場合は、多くの文献を読んでゼロから始めるように依頼するよりも、バグについて説明する方がよいでしょう.

于 2013-01-14T04:30:59.350 に答える
3

C++17 (ラムダ constexpr、自動テンプレート パラメーター、有効なテンプレートの非型値としてインライン) のおかげで、解決策が得られました。

//implementation
#include <utility>

template<auto X>
using constant = std::integral_constant<decltype(X), X>;

template<class T>
constexpr auto to_constant(T f) //should use && but clang has a bug that would make +f fail
{
   constexpr auto ptr = +f; //uses conversion operator to function pointer
   return constant<ptr>{}; //not yet implemented for gcc ("no linkage"), working with clang
}    

#define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })

//userland
template<auto Func>
constexpr void func(constant<Func>)
{
   constexpr decltype(auto) x = Func();
   static_assert(x == 3.14);
}

int main()
{
   func(constexpr_arg(3.14));
}

動作している証拠: https://godbolt.org/g/vWbyjE

また、このバージョンは、すべてのケースで機能するとは限りません (主に、マクロの引数が非 constexpr 値を使用しているにもかかわらず、constexpr の結果を生成する場合)。

このようなユースケースの場合: https://godbolt.org/g/DRZ5JM

gcc バージョンの場合 (今のところ移植可能です):

//implementation
template<class T>
struct constant
{
   static constexpr decltype(auto) value = T::getPtr()();
};

template<class T>
constexpr auto to_constant(T&& f) //remove the && if you want to be also compatible with clang
{
   constexpr auto ptr = +f; //uses conversion operator to function pointer
   struct A
   {
      static constexpr auto getPtr() { return ptr; }
   };
   return constant<A>{};
}    

#define constexpr_arg(...) to_constant([]{ return __VA_ARGS__; })

//userland
template<class Constant>
constexpr void func(Constant&&)
{
   static_assert(Constant::value == 3.14);
}

int main()
{
   func(constexpr_arg(3.14));
}

https://godbolt.org/g/LBCYfi

于 2017-11-03T04:19:54.283 に答える
2

使用std::integral_constant:

int x = std::integral_constant<int, g(0)>::value;
f(std::integral_constant<int, g(1)>::value);

g(n) がコンパイル時に評価されない場合、このコードはコンパイルされません。

于 2013-04-18T02:27:34.790 に答える