9

私はC++2011の新しいキーワードconstexprとかなり混乱しています。コンパイル時関数(特に数学関数)をコーディングするときに、constexprを使用する場所と、テンプレートメタプログラミングを使用する場所を知りたいです。たとえば、整数のpow関数を使用する場合:

// 1 : 
template <int N> inline double tpow(double x)
{
    return x*tpow<N-1>(x);
}
template <> inline double tpow<0>(double x)
{
    return 1.0;
}

// 2 :
constexpr double cpow(double x, int N)
{
    return (N>0) ? (x*cpow(x, N-1)) : (1.0);
}

// 3 :
template <int N> constexpr double tcpow(double x)
{
    return x*tcpow<N-1>(x);
}
template <> constexpr double tcpow<0>(double x)
{
    return 1.0;
}

2番目と3番目の関数は同等ですか?最善の解決策は何ですか?同じ結果が得られますか:

  • xがコンパイル時にわかっている場合
  • コンパイル時にxが不明な場合

constexprを使用する場合とテンプレートメタプログラミングを使用する場合

編集1:テンプレートの特殊化を含むようにコードが変更されました

4

2 に答える 2

9

テンプレートメタプログラミングの質問にこれほど遅く答えるべきではないでしょう。しかし、ここに行きます。

まず、constexprはVisual Studio 2012に実装されていません。Windows用に開発する場合は、忘れてください。私は知っている、それはひどい、私はそれを含まないためにマイクロソフトを嫌う。

それが邪魔にならないように、定数として宣言できるものはたくさんありますが、「コンパイル時にそれらを操作できる」という点では、実際には「定数」ではありません。例えば:

const int foo[5] = { 2, 5, 1, 9, 4 };
const int bar = foo[foo[2]]; // Fail!

コンパイル時にそこから読み取ることができると思いますよね?いいえ。しかし、あなたがそれをconstexprにすればあなたはそうすることができます。

constexpr int foo[5] = { 2, 5, 1, 9, 4 };
constexpr int bar = foo[foo[2]]; // Woohoo!

Constexprは、「定数伝播」の最適化に非常に適しています。つまり、コンパイル時に何らかの条件(おそらくメタプログラミング)に基づいて宣言された変数Xがある場合、それがconstexprである場合、コンパイラは、最適化を実行するときにそれを「安全に」使用できることを認識します。 a =(X * y);のような命令 そしてそれらをa=0に置き換えます。Xが0と評価された場合(および他の条件が満たされている場合)。

明らかに、これは素晴らしいことです。なぜなら、多くの数学関数では、定数の伝播により、(使いやすい)時期尚早の最適化が簡単にできるからです。

それらの主な用途は、かなり難解なこと(コンパイル時のバイトコードインタープリターをはるかに簡単に記述できるようにするなど)以外に、コンパイル時に呼び出して使用できる「関数」またはクラスを作成できるようにすることです。時間と実行時。

基本的には、C ++ 03の穴を埋めるだけで、コンパイラによる最適化に役立ちます。

では、あなたの3つのうちどれが「最高」ですか?

2は実行時に呼び出すことができますが、その他はコンパイル時のみです。それはかなり甘いです。

それにはもう少しあります。ウィキペディアには、「constexprでこれが可能」という非常に基本的な要約が記載されていますが、テンプレートメタプログラミングは複雑になる可能性があります。Constexprを使用すると、その一部がはるかに簡単になります。配列から読み取るという以外に、明確な例があればいいのにと思います。

良い数学的な例は、ユーザー定義の複素数クラスを実装したい場合だと思います。テンプレートメタプログラミングのみでconstexprを使用せずにコーディングするのは、桁違いに複雑になります。

では、いつconstexprを使用すべきではないのでしょうか。正直なところ、constexprは基本的に「MORECONSTを除くconst」です。通常、constを使用する場所であればどこでも使用できますが、実行時に呼び出されたときに、入力がconstでない場合に関数が非constとして動作する方法など、いくつかの注意点があります。

ええと OK、今のところこれですべてです。私はあまりにも疲れすぎて、これ以上言うことはできません。お役に立てば幸いです。お役に立てなかった場合は、遠慮なく反対票を投じてください。これを削除します。

于 2012-09-02T05:37:40.570 に答える
1

1番目と3番目が正しくありません。コンパイラは、tpow<N-1>評価する前にインスタンス化を試み(N>0) ?、無限のテンプレート再帰を取得します。N==1それを機能させるには、 (または)の特殊化が必要です==0。2ndはx、コンパイル時と実行時に既知の場合に機能します。

==0編集の専門分野の後に追加されました。これで、すべての関数がコンパイル時または実行時に機能しますx。1番目は常に非constexpr値を返します。2番目と3番目は、xNがconstexprの場合、constexprを返します。2番目Nはconstexprでない場合でも機能し、他の場合はconstexprが必要ですN(したがって、2番目と3番目は同等ではありません)。

constexprは2つの場合に使用されます。を記述するint N=10;場合、Nの値はコンパイル時に認識されますが、constexprではなく、たとえばテンプレート引数として使用することはできません。キーワードconstexprNは、コンパイル時の値として安全に使用できることをコンパイラーに明示的に指示します。2番目の用途はconstexpr関数としてです。C ++のサブセットを使用して、条件付きでconstexpr値を生成し、同等のテンプレート関数を劇的に単純化できます。constexpr関数の欠点の1つは、コンパイル時の評価が保証されていないことです。コンパイラは、実行時に評価を行うことを選択できます。テンプレート化された実装を使用すると、コンパイル時の評価が保証されます。

于 2012-09-02T05:02:20.433 に答える