C ++ 11およびC ++ 14のConstexpr指定子

C ++ 11の新機胜の1぀にconstexpr 。 これを䜿甚しお、コンパむル段階で蚈算される倉数、関数、さらにはオブゞェクトを䜜成できたす。 以前は、このような目的でテンプレヌトを䜿甚する必芁があったため、これは䟿利です。 しかし、すべおがそれほど単玔ではありたせん。 constexprあたり慣れおいない人は、コンパむル段階での蚈算に問題はないずいう印象を受けるかもしれたせん。 ただし、 constexpr匏には厳しい制限がありたす。

最初の郚分ではconstexprに぀いお、C ++ 14暙準でどのような倉曎が行われるかに぀いおconstexpr 、2番目の郚分ではconstexprの䜿甚䟋をconstexprたす。文字列内の数匏の結果を考慮するラむブラリです。
これを䜿甚しお、次のコヌドを蚘述できたす。
 constexpr auto x = "(4^2-9)/8+2/3"_solve; std::cout << "Answer is " << x; 

そしお、分数の圢匏での回答は、コンパむル段階で受信されたす。
Answer is 37/24
すぐに譊告したすが、このラむブラリのコヌドは理解しにくいです。
このトピックが興味深い人には、カットの䞋で歓迎したす

constexprずは䜕ですか


たず、 constexpr䜕であるかに぀いおのいく぀かの蚀葉。 既に述べたように、これを䜿甚するず、コンパむル段階でいく぀かの操䜜を実行できたす。 次のようになりたす。
 constexpr int sum (int a, int b) { return a + b; } void func() { constexpr int c = sum (5, 12); //        } 

constexpr関数


constexpr _ _ ()
関数の前にC ++ 11で远加されたconstexprは、コンパむル段階でパラメヌタ倀を蚈算できる堎合、返される倀もコンパむル段階で蚈算する必芁があるこずを意味したす。 コンパむル段階で少なくずも1぀のパラメヌタヌの倀が䞍明な堎合、関数はランタむムで起動されたすコンパむル゚ラヌは出力されたせん。

constexpr倉数


constexpr = expression;
この堎合のキヌワヌドは、定数を䜜成するこずを意味したす。 さらに、匏はコンパむル段階で認識される必芁がありたす。

この䟋を考えおみたしょう
 int sum (int a, int b) { return a + b; } constexpr int new_sum (int a, int b) { return a + b; } void func() { constexpr int a1 = new_sum (5, 12); // : constexpr- constexpr int a2 = sum (5, 12); // :  sum   constexp- int a3 = new_sum (5, 12); // :       int a4 = sum (5, 12); //  } 


constexpr倉数は定数 const ですが、定数はconstexpr倉数ではありたせん。

倉数のconstexprが「倱われた」堎合、コンパむル段階で倀を蚈算できたずしおも返されたせん。 constexprはcv指定子ではないため、const_castを䜿甚しおconstexpr指定子を远加するこずはできたせん constおよびvolatile 。 そのようなコヌドは機胜したせん
 constexpr int inc (int a) { return a + 1; } void func() { int a = inc (3); constexpr int b = inc (a); // : a   constexpr-, -       constexpr } 


関数パラメヌタヌをconstexprするこずはできたせん。 ぀たり、コンパむル段階でのみ機胜するconstexpr関数のみを䜜成するこずはできたせん。

constexpr関数もクラスで機胜したす。これに぀いおは埌で説明したす。

GCCは、バヌゞョン4.4からconstexprサポヌトし、Clangはバヌゞョン2.9からもサポヌトし、Visual Studio 2013はサポヌトしたせんただし、CTPはVisual Studio“ 14”でサポヌトを远加したした。

制限事項


これがどれほど䟿利かを理解したので、ハチミツの暜の䞭の軟膏にパを远加できたす。 そしお、かなり倧きなスプヌン。

constexpr倉数の制玄から始めたしょう。 constexpr倉数の型は、リテラル型、぀たり次のいずれかでなければなりたせん。

constexpr -variableは、次の条件を満たす必芁がありたす。

珍しいこずは䜕もないようです。 䞻な制限はconstexpr関数に課せられたす

* C ++ 14では、 voidもリテラル型になりたす。

constexprは、 return節ず1぀の新しい節の远加を陀いお、関数ず同じ制限に埓いたす。
すべおの非静的クラスメンバヌず基底クラスのメンバヌは、䜕らかの方法で初期化する必芁がありたす宣蚀時に初期化リストたたはクラスメンバヌの初期化を䜿甚するコンストラクタヌで。それらに割り圓おられる匏には、リテラルたたはconstexpr -variablesおよびconstexpr constexprのみを含める必芁がありたす。

関数内の倉数を初期化したりif-elseルヌプやif-else䜜成するこずはできたせん。 䞀方で、これらの制限は、コンパむラヌがコンパむル䞭に䜕らかの圢でプログラムの実行をモニタヌする必芁があるずいう事実によるものです再垰はルヌプよりも割り蟌みが容易です。 䞀方、耇雑な関数の䜜成には問題がありたす。

もちろん、すべお同じで、これらの可胜性はすべお実珟できたす。 ルヌプの代わりに再垰を䜿甚し、 if-else代わりに、「 ? : ? : "、そしお、倉数を䜜成する代わりに、関数の倀を䜿甚したす。

これはすべお、関数型プログラミングに非垞に䌌おいたす。 関数型プログラミング蚀語では、原則ずしお、倉数は開始できず、ルヌプもありたせん。 実際、関数を呌び出すこずができ、関数ぞのポむンタヌを䜿甚しお高次の関数を実装するこずもできたす残念ながら、constexpr構造では匿名関数ラムダは䜿甚できたせん。 たた、すべおのconstexpr関数は玔粋な関数ですパラメヌタヌにのみ䟝存し、結果のみを返したす。 constexprアルゎリズムを䜜成するには、少なくずも関数型プログラミングの初期知識が必芁です。

しかし、ここでC ++には構文に倧きな問題がありたす。匿名関数は䜿甚できず、関数のすべおのアクションは1぀の長い匏であり、「 ? : ? : »コヌドはたったく読めなくなりたす。 たた、これらすべおには、数癟行を占める可胜性のある䞍可解な゚ラヌメッセヌゞが䌎いたす。

しかし、問題はそれだけでは終わりたせん。 埌でよく䜿甚するconstexpr関数を䜜成する堎合、読み取り可胜な゚ラヌを返すず䟿利です。 ここでは、 static_assertがこれにちょうど適切であるず誀っお想定されたす。 ただし、関数パラメヌタはconstexprにできないため、 static_assertは䜿甚できたせん。これは、コンパむル時にパラメヌタ倀が認識されるこずが保蚌されない理由です。
゚ラヌを衚瀺する方法は 私が芋぀けた倚かれ少なかれ通垞の方法は、䟋倖をスロヌするこずです
 constexpr int div (int x, int y) { return (y == 0) ? throw std::logic_error ("x can't be zero") : (y / x); } 

コンパむル䞭の関数呌び出しの堎合、constructexpr関数にthrow構文を含めるこずができないずいう゚ラヌが衚瀺され、実行時に関数が䟋倖をスロヌしたす。
間違いを芋぀けるのは難しいでしょうが、少なくずも䜕か。
gcc 4.8.2の゚ラヌ䟋
Main.cpp1624 'MathCpp :: operator ""のconstexpr展開でconst char * "67 + 987 ^7-3 * 2*34-123+ 17 ^ 2/0 +-1 "、37ul '
MathCpp.h11528 'MathCppのconstexpr展開:: solvestr、size_tsize'
MathCpp.h120103 'MathCpp :: get_addsubMathCpp :: SMathDatastr、intsize、0'のconstexpr拡匵
MathCpp.h20989 'MathCpp :: const getr addsubdata.MathCpp :: SMathData :: createintMathCpp :: get_muldivdata.MathCpp :: SMathValue :: end+ 1、MathCpp :: get_muldivdata.MathCpp :: SMathValue :: value '
MathCpp.h21750 'MathCpp :: get_muldivdata.MathCpp :: SMathData :: createintdata.MathCpp :: SMathData :: start+ 1のconstexpr拡匵
MathCpp.h18183 'MathCpp :: _ get_muldivdata.MathCpp :: SMathData :: createintMathCpp :: get_powdata.MathCpp :: SMathValue :: end+のconstexpr拡匵で1、MathCpp :: get_powdata.MathCpp :: SMathValue :: value '
MathCpp.h38111゚ラヌ匏 '<throw-expression>'は定数匏ではありたせん
#define math_assertcondition、descriptionconditionINVALID_VALUEthrow std :: logic_errordescription、INVALID_VALUE
^
MathCpp.h19515泚マクロ「math_assert」の展開䞭
 math_assertfalse、「れロ陀算」

この゚ラヌ出力方法はただ蚀語暙準に準拠しおいたせん;コンパむラがconstexpr関数でconstexpr䜿甚できないずいう゚ラヌを垞にスロヌするこずを犁止するものは䜕もありたせん。 GCC 4.8.2ではこれは機胜したすが、Visual Studio "14"ではCTP C ++コンパむラはもうありたせん。

その結果、曞くのが難しく、デバッグするのが難しく、そのような構造を理解するのが難しいです。
しかし、すべおがそれほど悪くはありたせん。C++ 14では、非垞に倚くの制限が削陀されたす。

C ++ 14での倉曎


既に述べたように、新しい暙準では、 voidもリテラル型になり、たずえば、パラメヌタヌ倀の正圓性をチェックする関数を䜜成できるようになりたした。

2番目の小さな倉曎点は、 constexprクラスのメンバヌ関数が定数ではなくなったこずです。
C ++ 11では、次の行は同等でしたが、C ++ 14ではこれは圓おはたりたせん。
 class car { constexpr int foo (int a); // C++11:     const, C++14 -   constexpr int foo (int a) const; }; 

これの説明はここで芋぀けるこずができたす 。

そしお最埌に、䞻な倉曎により、 constexpr関数およびコンストラクタヌでほがすべおの構成を䜿甚できるようになりたした。
constexpr関数の本䜓には、 constexprを陀く任意の構成䜓を含めるこずができたす。


そしおconstexpr本䜓は、より忠実な条件を満たしおいるはずです。


その結果、C ++ 14をサポヌトするコンパむラが登堎した埌、通垞の関数ずほずんど倉わらないconstexpr関数を蚘述できるようになりたす。 それたでの間、非垞にわかりにくいコヌドを䜜成する必芁がありたす。

C ++ 11でconstexprを䜿甚する䟋


constexprの䜿甚䟋ずしお、文字列にある数匏の結果を読み取るラむブラリを提䟛したす。

そのため、次のようなコヌドを蚘述できるようにしたす。
 constexpr auto n = "(67+987^(7-3*2))*(34-123)+17^2+(-1)"_solve; std::cout << "Answer is " << n; 

別の新しいC ++ 11機胜がここで䜿甚されたすカスタムリテラル。 この堎合、結果の倀がconstexpr倉数に割り圓おられおいる堎合でも、コンパむル段階で関数が呌び出されるこずが保蚌されおいるため、これらはconstexprです。

カスタムリテラルは次のように宣蚀されたす。
 constexpr int operator "" _solve (const char* str, const size_t size); constexpr int solve (const char* str, const size_t size); constexpr int operator "" _solve (const char* str, const size_t size) { return solve (str, size); } 

次のマクロがアサヌトずしお䜿甚されたす。
 #define math_assert(condition,description) ((condition) ? 0 : (throw std::logic_error (description), 0)) 

ラむブラリは、加算、枛算、乗算、陀算、レむズができたす。たた、括匧のサポヌトもありたす。 これは、再垰降䞋を䜿甚しお実装されたす。

オペレヌタヌの優先順䜍は次のずおりです高いものから䜎いものぞ。
  1. 加算ず枛算
  2. 乗算ず陀算
  3. べき乗

数倀、床、合蚈などを読み取る関数は、1぀のパラメヌタヌ SMathData構造䜓を取りたす。 文字列、サむズ、 start倉数を保存したす-読み取りを開始する堎所
 struct SMathData { constexpr SMathData (const char* _str, const int _size, const int _start) : str (_str), size (_size), start (_start) {} constexpr SMathData create (const int _start) const { return SMathData (str, size, _start); } constexpr char char_start() const { return char_at (start); } constexpr char char_at (const int pos) const { return (pos >= 0 && pos < size) ? str[pos] : ((pos == size) ? 0 : (math_assert (false, "Internal error: out of bounds"), 0)); } const char* str; const int size; const int start; }; 

そしお、これらの関数はSMathValue構造䜓をSMathValueたす。 カりントされた倀はその䞭に保存され、endは、数倀、金額、補品、たたは䜕かの終わりが曞き蟌たれる倉数です。
 struct SMathValue { constexpr SMathValue (const int _value, const int _end) : value (_value), end (_end) {} constexpr SMathValue add_end (int dend) const { return SMathValue (value, end + dend); } const int value; const int end; }; 


番号を読み取るには、3぀の機胜メむン1぀ず補助2぀がありたす。
 //   (  ). constexpr SMathValue get_number (const SMathData data); //        (    ). //  positive == true,     ,   false -  . i -    . constexpr SMathValue _get_number (const SMathData data, const int i, const bool positive); //        (start -  ). constexpr int _get_number_end (const SMathData data); constexpr SMathValue get_number (const SMathData data) { return (data.char_start() == '-') ? (math_assert (data.char_at (data.start + 1) >= '0' && data.char_at (data.start + 1) <= '9', "Not a digit"), _get_number (data.create (data.start + 1), _get_number_end (data.create (data.start + 1)), false)) : (math_assert (data.char_start() >= '0' && data.char_start() <= '9', "Digit required"), _get_number (data, _get_number_end (data), true)); } constexpr SMathValue _get_number (const SMathData data, const int i, const bool positive) { return (i >= data.start) ? SMathValue (_get_number (data, i - 1, positive).value * 10 + (positive ? 1 : -1) * (data.char_at (i) - '0'), i) : SMathValue (0, data.start - 1); } constexpr int _get_number_end (const SMathData data) { return (data.char_start() >= '0' && data.char_start() <= '9') ? _get_number_end (data.create (data.start + 1)) : (data.start - 1); } 

これは非垞に耇雑な蚭蚈です。 get_numberは、珟圚のむンデックスが有効であるこずを確認し、 get_numberを呌び出しお、最初の反埩ずしお数倀の末尟を枡したす数倀は右から巊に読み取られたす。

ブラケットを䜿甚する
 // get branum -   get bracket or number. constexpr SMathValue get_branum (const SMathData data); constexpr SMathValue get_branum (const SMathData data) { return (data.char_start() == '(') ? (math_assert (data.char_at (get_addsub (data.create (data.start + 1)).end + 1) == ')', "')' required"), get_addsub (data.create (data.start + 1)).add_end (1)) : get_number (data); } 

珟圚のむンデックスに番号がある堎合、関数はget_number呌び出しget_number 。それ以倖の堎合、関数は括匧内の匏を考慮したす。

次に、べき乗関数がありたす。
 //      . constexpr SMathValue get_pow (const SMathData data); //  .  ,  start         ( ), //     '^',   . value -    ( ). constexpr SMathValue _get_pow (const SMathData data, const int value); constexpr SMathValue get_pow (const SMathData data) { return _get_pow (data.create (get_branum (data).end + 1), get_branum (data).value); } constexpr SMathValue _get_pow (const SMathData data, const int value) { return (data.char_start() == '^') ? _get_pow (data.create // start (get_branum (data.create (data.start + 1)).end + 1), // value math_pow (value, get_branum (data.create (data.start + 1)).value)) : SMathValue (value, data.start - 1); } 

_get_pow関数は、珟圚の文字が'^'こずを確認したす。 その堎合、関数はそれ自䜓より正確にはget_pow を呌び出し、 get_powに、 get_powの範囲のvalueず等しい新しい倀を枡したす。

文字列"25" 、 get_pow呌び出された堎合に正しく凊理されるこずがget_powたした。 この堎合、番号は単に読み取られるため、その埌返されたす。
math_powは、敎数に䞊げる単玔なconstexpr関数です。
Math_powの実装
 constexpr int math_pow (const int x, const int y); constexpr int _math_pow (const int x, const int y, const int value); constexpr int math_pow (const int x, const int y) { return math_assert (y >= 0, "Power can't be negative"), _math_pow (x, y.to_int(), 1); } constexpr int _math_pow (const int x, const int y, const int value) { return (y == 0) ? value : (x * _math_pow (x, y - 1, value)); } 


補品ず郚門は1぀の機胜で凊理されたす。
 //      . constexpr SMathValue get_muldiv (const SMathData data); //  .  _get_pow. constexpr SMathValue _get_muldiv (const SMathData data, const int value); constexpr SMathValue get_muldiv (const SMathData data) { return _get_muldiv (data.create (get_pow (data).end + 1), get_pow (data).value); } constexpr SMathValue _get_muldiv (const SMathData data, const int value) { return (data.char_start() == '*') ? _get_muldiv (data.create // start (get_pow (data.create (data.start + 1)).end + 1), // value value * get_pow (data.create (data.start + 1)).value) : ((data.char_start() == '/') ? (get_pow (data.create (data.start + 1)).value == 0) ? math_assert (false, "Division by zero") : _get_muldiv (data.create // start (get_pow (data.create (data.start + 1)).end + 1), // value value / get_pow (data.create (data.start + 1)).value) : SMathValue (value, data.start - 1)); } 

この構造を理解するこずはかなり難しく、曞くこずも困難です。 ここで、珟圚の文字が'*'であるかどうかを確認したす。そうである堎合、関数はvalueを読み取り番号たたは匏で乗算しお自分自身を呌び出したす。 '/'関数は同様に動䜜'/'たすが'/'前に分母がれロに等しくないずいうチェックがありたす。 珟圚の文字が'*'たたは'/'でない堎合、倀が単に返されたす。

同様に、合蚈ず差でも起こりたす
Get_addsubの実装
 constexpr SMathValue get_addsub (const SMathData data); constexpr SMathValue _get_addsub (const SMathData data, const CMathVariable value); constexpr SMathValue get_addsub (const SMathData data) { return _get_addsub (data.create (get_muldiv (data).end + 1), get_muldiv (data).value); } constexpr SMathValue _get_addsub (const SMathData data, const CMathVariable value) { return (data.char_start() == '+') ? _get_addsub (data.create // start (get_muldiv (data.create (data.start + 1)).end + 1), // value value + get_muldiv (data.create (data.start + 1)).value) : ((data.char_start() == '-') ? _get_addsub (data.create // start (get_muldiv (data.create (data.start + 1)).end + 1), // value value - get_muldiv (data.create (data.start + 1)).value) : SMathValue (value, data.start - 1)); } 

get_muldivおよび_getmuldivそれぞれget_muldivおよび_getmuldivず同様に_getmuldivたす。

そしお最埌に、関数solveを実装するこずは残っおいたす
 constexpr CMathVariable solve (const char* str, const size_t size); // get_value ,      // ( ,  value.end == size),   . constexpr int get_value (const int size, const SMathValue value); constexpr int solve (const char* str, const size_t size) { return get_value (static_cast<int> (size), get_addsub (SMathData (str, static_cast<int> (size), 0))); } constexpr int get_value (const int size, const SMathValue value) { return math_assert (value.end + 1 == size, "Digit or operator required"), value.value; } 

最埌にできるこずは、分子ず分母を別々の倉数ずしお保存する数倀のクラスを䜿甚するこずです。 特別なものはありたせん。すべおの関数ずコンストラクタヌにconstexprがconstexpr 。
独自の数字のクラス
 class CMathVariable { private: int64_t numerator_; uint64_t denominator_; constexpr CMathVariable (int64_t numerator, uint64_t denominator); constexpr int64_t sign_ (int64_t a) const; constexpr uint64_t gcd_ (uint64_t a, uint64_t b) const; constexpr CMathVariable reduce_() const; public: constexpr explicit CMathVariable (int number); constexpr CMathVariable operator + (const CMathVariable& n) const; constexpr CMathVariable operator - (const CMathVariable& n) const; constexpr CMathVariable operator * (const CMathVariable& n) const; constexpr CMathVariable operator / (const CMathVariable& n) const; constexpr int64_t numerator() const; constexpr uint64_t denominator() const; constexpr bool is_plus_inf() const; constexpr bool is_menus_inf() const; constexpr bool is_nan() const; constexpr bool is_inf() const; constexpr bool is_usual() const; constexpr bool is_integer() const; constexpr int to_int() const; constexpr int force_to_int() const; constexpr double to_double() const; friend constexpr CMathVariable operator - (const CMathVariable& n); friend constexpr CMathVariable operator + (const CMathVariable& n); friend std::ostream& operator << (std::ostream& os, const CMathVariable& var); }; constexpr CMathVariable operator - (const CMathVariable& n); constexpr CMathVariable operator + (const CMathVariable& n); std::ostream& operator << (std::ostream& os, const CMathVariable& var); constexpr CMathVariable::CMathVariable (int number) : numerator_ (number), denominator_ (1) { } constexpr CMathVariable::CMathVariable (int64_t numerator, uint64_t denominator) : numerator_ (numerator), denominator_ (denominator) { } constexpr int64_t CMathVariable::sign_ (int64_t a) const { return (a > 0) - (a < 0); } constexpr uint64_t CMathVariable::gcd_ (uint64_t a, uint64_t b) const { return (b == 0) ? a : gcd_ (b, a % b); } constexpr CMathVariable CMathVariable::reduce_() const { return (numerator_ == 0) ? CMathVariable (0, sign_ (denominator_)) : ((denominator_ == 0) ? CMathVariable (sign_ (numerator_), 0) : CMathVariable (numerator_ / gcd_ (static_cast<uint64_t> (std::abs (numerator_)), denominator_), denominator_ / gcd_ (static_cast<uint64_t> (std::abs (numerator_)), denominator_))); } constexpr int64_t CMathVariable::numerator() const { return numerator_; } constexpr uint64_t CMathVariable::denominator() const { return denominator_; } constexpr bool CMathVariable::is_plus_inf() const { return denominator_ == 0 && numerator_ > 0; } constexpr bool CMathVariable::is_menus_inf() const { return denominator_ == 0 && numerator_ < 0; } constexpr bool CMathVariable::is_nan() const { return denominator_ == 0 && numerator_ == 0; } constexpr bool CMathVariable::is_inf() const { return denominator_ == 0 && numerator_ != 0; } constexpr bool CMathVariable::is_usual() const { return denominator_ != 0; } constexpr bool CMathVariable::is_integer() const { return denominator_ == 1; } constexpr int CMathVariable::to_int() const { return static_cast<int> (numerator_ / denominator_); } constexpr int CMathVariable::force_to_int() const { return (!(denominator_ == 1 && static_cast<int> (numerator_) == numerator_) ? (throw std::logic_error ("CMathVariable can't be represented by int"), 0) : 0), to_int(); } constexpr double CMathVariable::to_double() const { return static_cast<double> (numerator_) / denominator_; } constexpr CMathVariable CMathVariable::operator + (const CMathVariable& n) const { return CMathVariable ( static_cast<int64_t> (n.denominator_ / gcd_ (denominator_, n.denominator_)) * numerator_ + static_cast<int64_t> (denominator_ / gcd_ (denominator_, n.denominator_)) * n.numerator_, denominator_ / gcd_ (denominator_, n.denominator_) * n.denominator_).reduce_(); } constexpr CMathVariable CMathVariable::operator - (const CMathVariable& n) const { return CMathVariable ( static_cast<int64_t> (n.denominator_ / gcd_ (denominator_, n.denominator_)) * numerator_ - static_cast<int64_t> (denominator_ / gcd_ (denominator_, n.denominator_)) * n.numerator_, denominator_ / gcd_ (denominator_, n.denominator_) * n.denominator_).reduce_(); } constexpr CMathVariable CMathVariable::operator * (const CMathVariable& n) const { return CMathVariable ( numerator_ * n.numerator_, denominator_ * n.denominator_).reduce_(); } constexpr CMathVariable CMathVariable::operator / (const CMathVariable& n) const { return CMathVariable ( numerator_ * static_cast<int64_t> (n.denominator_) * (n.numerator_ ? sign_ (n.numerator_) : 1), denominator_ * static_cast<uint64_t> (std::abs (n.numerator_))).reduce_(); } constexpr CMathVariable operator + (const CMathVariable& n) { return n; } constexpr CMathVariable operator - (const CMathVariable& n) { return CMathVariable (-n.numerator_, n.denominator_); } std::ostream& operator << (std::ostream& stream, const CMathVariable& var) { if (var.is_plus_inf()) stream << "+inf"; else if (var.is_menus_inf()) stream << "-inf"; else if (var.is_nan()) stream << "nan"; else if (var.denominator() == 1) stream << var.numerator(); else stream << var.numerator() << " / " << var.denominator(); return stream; } 


その埌、再垰降䞋のコヌドをわずかに倉曎し、必芁な結果を取埗する必芁がありたす。
constexpr-functionsで再垰降䞋を蚘述するのに玄1日かかりたしたが、通垞の再垰降䞋は1時間で問題なく曞き蟌たれたす。問題は、括匧ずの混同、デバッグの耇雑さ、理解できない゚ラヌ、そしお考えられないアヌキテクチャ今は、再垰的な降䞋であっおも、すべおを泚意深く怜蚎する必芁がありたすです。

このラむブラリのリポゞトリはこちらですhttps : //bitbucket.org/jjeka/mathcpp

欠点や質問がある堎合は、曞いおください
PS C ++ 11/14専甚のハブを䜜成するずきが来たず思いたす。

Source: https://habr.com/ru/post/J228181/


All Articles