非定数定数匏

// <コヌド>

int main  
{
constexpr int a = f   ;
constexpr int b = f   ;

static_assert  a = b 、 "fail"  ;
}

䞊蚘のフラグメントにコメントの代わりにfの定矩を挿入しお、 aがb以倖の倀を取埗するこずは可胜ですか

「もちろんそうではありたせん」あなたは少し考えお蚀う。 実際、䞡方の倉数はconstexpr指定子で宣蚀されたす 。぀たり、 fもconstexpr関数でなければなりたせん。 constexpr関数はコンパむル時に実行できるこずを誰もが知っおいたす。その結果、プログラムのグロヌバルな状態に䟝存したり、プログラムを倉曎したりするべきではありたせん蚀い換えるず、 それらはcleanでなければなりたせん 。 枅浄床ずは、関数が同じ匕数で呌び出されるたびに同じ倀を返す必芁があるこずを意味したす。 fは匕数なしで䞡方の時間で呌び出されるため、倉数aずbに割り圓おられる同じ倀を䞡方の時間で返す必芁がありたす...

1週間前、私はこれが真実であるこずを知っおいたので、未定矩の動䜜を避けお、䞊蚘のスニペットでstatic_assertを枡すこずは䞍可胜だず本圓に思っおいたした。

私は間違っおいたした。

内容



免責事項この蚘事で説明する手法は、「C ++の暗い深みに没頭する別のトリッキヌなハック」ず䜍眮付けられおいたす。 最初にすべおの萜ずし穎以䞋の蚘事で詳现に説明したすを孊習せずに、実皌働環境で䜿甚するこずはお勧めしたせん。

免責事項は、他のサむトでこの蚘事のコメントを読んだ埌に远加されたもので、その目的の誀解を芋぀けたした。 私はあなたの寝宀の倖で説明されたテクニックを䜿甚するこずを承認したせんそのような䜿甚の結果を考慮しないで。


なぜこれが必芁なのでしょうか


蚘事の冒頭で提起された問題を解決したら、コンパむルプロセスに可倉状態を正垞に远加できたす蚀い換えるず、呜什型メタプログラムを蚘述できたす。

ご泚意 trans可倉定数定数を「倉数」ずしお䜿甚するず、メタプログラムの呜什性を簡単に远加できるず読者は䞻匵するかもしれたせん。 したがっお、問題を解決するには、 define f__COUNTER__たたはそのようなものを䜿甚できたす。

残念ながら、これは最も単玔な堎合にのみ機胜したす。これは、プリプロセッサがプログラムテキスト内でマクロに遭遇するずすぐにマクロを展開し、蚀語自䜓の構文構造を無芖するためです。 したがっお、メタ関数のむンスタンス化の順序が重芁になるか、倉数を䞀床読み取っお倉曎する以倖の䜕かが必芁になるずすぐに、マクロはその胜力で圹に立たなくなりたす。

䞀芋、これは小さくお無邪気な抂念のように思えるかもしれたせんが、この蚘事で説明する手法を䜿甚するず、以前は非垞に耇雑なコヌドを必芁ずしたり、たったく解決できなかった倚くの問題を解決できたす。

䟋

コンパむル時カりンタヌ


C1 = ... を䜿甚したす。

int constexpr a = C1 :: next   ; // = 1
int constexpr b = C1 :: next   ; // = 2
int constexpr c = C1 :: next   ; // = 3

コンパむル時メタタむプコンテナヌ


LX = ... を䜿甚したす。

LX :: push < void 、 void 、 void 、 void >   ;
LX :: set < 0 、 クラス Hello >   ;
LX :: set < 2 、 クラス World >   ;
LX :: pop   ;

LX :: 倀 <> x ; // type_list <class Hello、void、class World>

他のアむデア




予備情報


泚このパヌトでは、問題の解決に関連する技術的な偎面に぀いお詳しく説明したす。 したがっお、最も経隓豊富なたたはせっかちな読者はそれをスキップできたす。 お菓子のためだけにここにいる堎合は、すぐに決定に進みたす。
泚少なくずも、゜リュヌションコヌドが正確にどのように、なぜ機胜するのかそしお暙準の芳点からは合法ですに興味がある堎合は、少なくずもこの郚分をざっず読むこずをお勧めしたす。

友達キヌワヌド


C ++のフレンドシップ関係は、別の゚ンティティにそのプラむベヌトメンバヌおよび保護されたメンバヌぞのアクセスを提䟛するだけでなく䜿甚できたす。 次の非垞に単玔な䟋に぀いお考えたす。

クラス A ;
ボむドタッチ A   ;

クラス A
{
友人 ボむドタッチ A   ;
intメンバヌ;
} ;

ボむドタッチ A  ref 
{
ref。 メンバヌ = 123 ; // OK、 `void touchA`はクラスAの友人です
}

int main  
{
A a ; a。 メンバヌ = 123 ; //無効、メンバヌ「A ::メンバヌ」プラむベヌト
A b ; タッチ b  ;
}

最初に、グロヌバルスコヌプでvoidタッチA関数を宣蚀し、次にクラスAに フレンドリに宣蚀し、最埌にグロヌバルスコヌプで定矩したす。

同じ成功を収めお、次の䟋のように、䜕も倉曎せずに、クラスA内にvoid touchAの宣蚀ず定矩を組み合わせお盎接配眮できたす。

クラス A
{
フレンド ボむドタッチ A  ref 
{
ref。 メンバヌ = 123 ;
}

intメンバヌ;
} ;

int main  
{
A b ; タッチ b  ; // OK
}

friendを䜿甚するためのこれら2぀のアプロヌチが完党に同等ではないこずは非垞に重芁ですただし、この特定のケヌスではそうであるように思われるかもしれたせん。

最埌の䟋では、 ボむドタッチAは、クラスAを囲む最も近い名前空間のスコヌプに暗黙的に配眮されたすが、 Koenig怜玢 ADLによっおのみアクセスできたす。

クラス A
{
公開 
A  int  ;

フレンド ボむドタッチ A  { ... }
} ;

int main  
{
A b = 0 ; タッチ b  ; // OK、 `void touchA`はADLを介しお怜出されたす
タッチ 0  ; //間違っおいたす、匕数の型は `int`で、ADLはクラスをスキャンしたせん` A`
}

以䞋の暙準からの抜粋は䞊蚘を繰り返したすが、行間に曞かれおいるこずに集䞭しおほしいです同様に重芁だからです

7.3.1.2/3名前空間 メンバヌ定矩 [namespace.memdef] p3
名前空間内で最初に宣蚀された各名前は、その名前空間のメンバヌです。 非ロヌカルクラス内のフレンド宣蚀が最初にクラス、関数、クラステンプレヌト、たたは関数テンプレヌトを宣蚀する堎合、それらは最も近くにある名前空間のメンバヌになりたす。 フレンド宣蚀だけでは、非修食3.4.1たたは修食3.4.3の名前怜玢で名前が衚瀺されるこずはありたせん。

フレンド宣蚀を介しお入力された名前は、この宣蚀が眮かれおいるクラスの名前ず、実際にはこのクラスずの関係に関係しおいる必芁があるこずはどこにも蚘茉されおいないこずに泚意しおください。

#include <iostream>

クラス A
{
公開 
A  int  { }
友人 ボむド f  A  ;
} ;

ボむド g  A  ;

クラス B
{
友達 ボむド f  A 
{
std :: cout << "hello world" << std :: endl ;
}

クラス C
{
友達 ボむド g  A 
{
std :: cout << "dlrow olleh" << std :: endl ;
}
} ;
} ;

int main  
{
A a  0  ;
f  a  ;
g  1  ;
}

したがっお、 fはクラスBずは関係がありたせん。ただし、クラスBは 、その内郚で盎接フレンドずしお定矩されおいるずいう事実を陀き、そのようなコヌドは絶察に正しいです。

泚これらの考慮事項は非垞に簡単に思えるかもしれたせんが、䜕が起こっおいるのか疑問がある堎合は、コンパむラヌを芋぀けお䞊蚘のスニペットを詊しおみるこずをお勧めしたす。

定数匏のルヌル


constexprに関連するルヌルは倚数あり、この導入をより厳密か぀詳现にするこずができたすが、簡単に説明したす。


泚このリストは䞍完党で厳密ではありたせんが、ほずんどの堎合にconstexpr゚ンティティず定数匏がどのように動䜜するかを瀺しおいたす。

定数匏の操䜜のすべおの偎面を詳现に怜蚎する代わりに、呌び出し時にただ定矩されおいない関数呌び出しを定数匏に含めないようにする芏則に焊点を圓おたす。

constexpr int f   ;
ボむドむンダむレクション  ;

int main  
{
constexpr int n = f   ; //無効、 `int f`はただ定矩されおいたせん
むンダむレクション  ;
}

constexpr int f  
{
0を 返し たす 。
}

無効な間接指定 
{
constexpr int n = f   ; // OK
}

ここでは、 constexpr -function int fが宣蚀 されおいたすが、 mainで定矩されおいたせんが 、むンダむレクション内に定矩がありたすボディが開始するたでにむンダむレクション定矩がすでに提䟛されおいるため。 したがっお、 むン ダむレクション内では、 constexpr関数fの呌び出しは定数匏になり、 nの初期化は正しくなりたす。

匏が定数であるこずを確認する方法


特定の匏が定数であるかどうかを確認する方法はいく぀かありたすが、それらのいく぀かは他のものよりも実装が困難です。

経隓豊富なC ++開発者は、ここでSFINAE 眮換の倱敗ぱラヌではないの抂念をうたく適甚する機䌚をすぐに芋お、正しいでしょう。 しかし、SFINAEが提䟛する胜力は、かなり耇雑なコヌドを蚘述する必芁性ず結び぀いおいたす。

ご泚意 あたり
たずえば、
constexpr int x = 7 ;

テンプレヌト < typename >
std :: false_type isConstexpr  ...  ;

template < typename T 、 T test =  15 * 25 - x  > //テスト匏
std :: true_type isConstexpr  T *  ;

constexpr bool value = std :: is_same < decltype  isConstexpr < int >  nullptr   、 std :: true_type > :: value ; // true

noexcept挔算子を䜿甚しお問題を解決する方がはるかに簡単です。 この挔算子は、䟋倖をスロヌできない匏に察しおtrueを返し、そうでない堎合はfalseを返したす 。 特に、すべおの定数匏は䟋倖をスロヌしないず芋なされたす。 これでプレむしたす。

constexpr int f   ;
ボむドむンダむレクション  ;

int main  
{
// `f`は定数匏ではありたせん。
//その定矩が欠萜しおいる間

constexpr bool b = noexcept  f    ; // false
}

constexpr int f  
{
0を 返し たす 。
}

無効なむンダむレクション 
{
//そしお今

constexpr bool b = noexcept  f    ; // true
}

泚珟圚、 clangにはバグが含たれおいたす。これは、チェックされた匏が定数であっおも、 noexceptがtrueを返さないためです 。 回避策は、この蚘事の付録に蚘茉されおいたす。

テンプレヌトのむンスタンス化のセマンティクス


C ++暙準に、ほずんどのプログラマにずっお本圓の挑戊をもたらす郚分がある堎合、それは間違いなくテンプレヌトに関連しおいたす。 ここでテンプレヌトのむンスタンス化のあらゆる偎面を怜蚎するこずにした堎合、蚘事は非垞に倧きくなり、少なくずも数時間は読み続けるこずになりたす。

これは私たちが目指しおいるこずではないので、代わりに、問題の解決策がどのように機胜するかを理解するために必芁なむンスタンス化の基本原則に぀いおのみお話ししようずしたす。

泚このセクションの内容は、テンプレヌトをむンスタンス化するための完党なリファレンスではないこずに泚意しおください。 それに蚘茉されおいるルヌルには䟋倖がありたす。さらに、蚘事の範囲を超えおいるいく぀かの事実を意図的に省略したした。

基本原則


最小の蟞曞
  • テンプレヌトの特殊化は、テンプレヌトパラメヌタを特定の匕数に眮き換えるこずにより、テンプレヌトから取埗される実装です。 テンプレヌト<typename T>クラスFoo-テンプレヌト。 Foo <int>は圌の専門分野です。 プログラマは、その動䜜が䞀般化されたものず異なるこずが必芁な堎合、特定の匕数セットに察しおテンプレヌトの完党たたは郚分的な特殊化を個別に提䟛できたす。 関数テンプレヌトでは郚分的な特殊化は䜿甚できたせん。
  • テンプレヌト特化のむンスタンス -汎甚テンプレヌトコヌドから特殊化コヌドをコンパむラヌで取埗したす。 簡朔にするために、圌らはしばしば特定の匕数を䜿甚しおテンプレヌトをむンスタンス化するこずに぀いお話し、「特殊化」ずいう蚀葉を省略したす。
  • むンスタンス化は明瀺的たたは暗黙的です。 明瀺的にむンスタンス化する堎合、プログラマヌは特定の匕数を䜿甚しおテンプレヌトをむンスタンス化する必芁があるこずをコンパむラヌに個別に通知したす。䟋 template class Foo <int> さらに、必芁に応じお、コンパむラヌはそれ自䜓で特殊化を暗黙的にむンスタンス化できたす。

以䞋は、タスクに最も盎接関係する原則の簡朔なリストです。


むンスタンス化ポむント


クラスたたは関数のテンプレヌトの特化が蚀及されおいるコンテキストがそのむンスタンス化を必芁ずするずきはい぀でも、いわゆる むンスタンス化ポむント 実際には、汎甚テンプレヌトコヌドから特殊化コヌドを生成するずきにコンパむラが存圚できる堎所の1぀を決定したす。

ネストされたテンプレヌトの堎合、倖郚テンプレヌトYのパラメヌタヌに䟝存するコンテキストで内郚テンプレヌトの特殊化Xが蚀及されおいる堎合、この特殊化のむンスタンス化ポむントは倖郚テンプレヌトの察応するポむントに䟝存したす。


ネストされたテンプレヌトがない堎合、たたはコンテキストが倖郚テンプレヌトのパラメヌタヌに䟝存しない堎合、むンスタンス化ポむントは、特殊化Xが蚀及された「最もグロヌバルな」゚ンティティの宣蚀/定矩のポむントDに関連付けられたす。


関数テンプレヌト特化生成


関数テンプレヌトの特殊化には、任意の数のむンスタンス化ポむントを含めるこずができたすが、コンパむラヌがどのむンスタンス化ポむントを遞択しおコヌドを生成しおも、テンプレヌト内の匏は同じ意味を持぀必芁がありたすそうでない堎合、プログラムは正しくないず芋なされたす

簡単にするために、C ++暙準では、むンスタンス化された関数テンプレヌトの特殊化には、 翻蚳単䜍の最埌に远加のむンスタンス化ポむントがあるこずを芏定しおいたす。

名前空間 N
{
struct X { / *特別に空癜のたた* / } 。

void func  X 、 int  ;
}

テンプレヌト < typename T >
void call_func  T val 
{
func  val 、 3.14f  ;
}

int main  
{
call_func  N :: X { }  ;
}

//最初のむンスタンス化ポむント

名前空間 N
{
float func  X 、 float  ;
}

// 2番目のむンスタンス化ポむント

この䟋では、関数void call_func <N :: X>N :: Xのむンスタンス化の2぀のポむントがありたす。 最初はmainの定矩の盎埌 call_funcはその内郚で呌び出されるためで、2番目はファむルの最埌です。

call_func <N :: X>の動䜜は、特殊化コヌドを生成するコンパむラヌに応じお倉化するため、この䟋は正しくありたせん。


クラステンプレヌト専門化の生成


クラステンプレヌトを特化するために、最初のものを陀くすべおのむンスタンス化ポむントは無芖されたす。 これは、実際には、むンスタンス化が必芁なコンテキストでコンパむラが最初に蚀及されたずきに、コンパむラが特殊化コヌドを生成する必芁があるこずを意味したす。

名前空間 N
{
struct X { / *特別に空癜のたた* / } 。

void func  X 、 int  ;
}

template < typename T > struct A { using type = decltype  func  T { } 、 3.14f   ; } ;
template < typename T > struct B { type = decltype  func  T { } 、 3.14f  を䜿甚しお ; } ;

//むンスタンス化ポむントA

int main  
{
A < N :: X > a ;
}

名前空間 N
{
float func  X 、 float  ;
}

//むンスタンス化ポむントB

ボむド g  
{
A < N :: X > :: タむプ a ; //間違っおいたす、タむプは `void`になりたす
B < N :: X > :: タむプ b ; // OK、タむプは「float」になりたす
}

ここでは、むンスタンス化ポむントA <N :: X>はmainの盎前になり、むンスタンス化ポむントB <N :: X>は gの盎前になりたす。

すべおをたずめる


クラステンプレヌト内のフレンド宣蚀に関連付けられたルヌルは、次の定矩䟋ではfuncshortずfuncfloatが生成され、それぞれ特殊化A <short>ずA <float>のむンスタンス化ポむントに配眮されるこずを瀺しおいたす。

constexpr int func  short  ;
constexpr int func  float  ;

テンプレヌト < typename T >
構造䜓 A
{
友達 constexpr int func  T  { 0を 返す ; }
} ;

テンプレヌト < typename T >
A < T >むンダむレクション 
{
return { } ;
}

//1

int main  
{
むンダむレクション< short >   ; //2
むンダむレクション< float >   ; //3
}

蚈算匏に関数テンプレヌトの特殊化の呌び出しが含たれる堎合、この特殊化の戻り倀の型を完党に定矩する必芁がありたす。 したがっお、行2および3の呌び出しは、むンスタンス化ポむント順番にmainの前の前に、 間接化特殊化ずずもに特殊化Aの暗黙的なむンスタンス化を必芁ずしたす。

行2および3に到達する前に、関数funcshortおよびfuncfloatが 宣蚀 されおいるが、 定矩されおいないこずが重芁です。 これらの行の達成により、特殊化Aのむンスタンス化が発生する堎合、これらの関数の定矩は衚瀺されたすが、これらの行の隣ではなく、ポむント1に配眮されたす。


解決策


予備的な情報が、このセクションで説明する゜リュヌションで䜿甚される蚀語のすべおの偎面を十分に明らかにするこずを願っおいたす。

念のために、゜リュヌションがどのように、なぜ機胜するかを完党に理解するために、次の偎面に぀いおのアむデアが必芁であるこずを思い出させおください。


実装


constexpr int flag  int  ;

テンプレヌト < typenameタグ>
構造ラむタヌ
{
友達 constexpr intフラグタグ
{
0を 返し たす 。
}
} ;

テンプレヌト < bool B 、 typename Tag = int >
struct dependent_writer  writer <タグ> { } ;

テンプレヌト <
bool B = noexcept  flag  0   、
int = sizeof  dependent_writer < B > 
>
constexpr int f  
{
リタヌン B ;
}

int main  
{
constexpr int a = f   ;
constexpr int b = f   ;

static_assert  a = b 、 "fail"  ;
}

泚 clangはこのコヌドで䞍正な動䜜を瀺したす 。回避策はアプリケヌションで利甚できたす 。
ご泚意 trans Visual Studio 2015の芖芚的なキュヌは、 fの倉曎にも「気付かない」。 ただし、コンパむル埌、 aずbの倀は異なりたす。

しかし、それはどのように機胜したすか


予備情報を読んだ堎合、䞊蚘の解決策を理解するこずで問題が生じるこずはありたせんが、その堎合でも、さたざたな郚分の動䜜原理の詳现な説明が興味深い堎合がありたす。

このセクションでは、゜ヌスコヌドをステップごずに分析し、各フラグメントに぀いお簡単な説明ず正圓性を瀺したす。

「倉数」


プログラムの各ポむントで、 constexpr関数は2぀の状態のいずれかになりたす。既に定矩されおおり、定数匏から呌び出すこずができるかどうかです。 これら2぀の状況のいずれかのみが可胜ですあいたいな動䜜を蚱可しない限り。

通垞、 constexpr関数は関数ず芋なされ、正確に䜿甚されたすが、䞊蚘のおかげで、 boolに䌌た型を持぀「倉数」ず考えるこずができたす。 そのような各「倉数」は、「定矩枈み」たたは「未定矩」の2぀の状態のいずれかです。

constexpr int flag  int  ;

このプログラムでは、 フラグ関数は同様のトリガヌです。 どこでも関数ずしお呌び出すのではなく、「倉数」ずしおの珟圚の状態にのみ関心がありたす。

修食子


writerは、むンスタンス化されるず、その名前空間この堎合はグロヌバルで関数の定矩を䜜成するクラステンプレヌトです。 タグテンプレヌトパラメヌタは、定矩が䜜成される関数の特定のシグネチャを定矩したす。

テンプレヌト < typenameタグ>
構造ラむタヌ
{
友達 constexpr intフラグタグ
{
0を 返し たす 。
}
} ;

予定通り、 constexpr -functionsを「倉数」ず芋なす堎合、テンプレヌト匕数Tを䜿甚しお ラむタヌを䜜成するず、「倉数」のシグネチャint funcTが「定矩枈み」䜍眮に無条件に倉換されたす。

プロキシ


テンプレヌト < bool B 、 typename Tag = int >
struct dependent_writer  writer <タグ> { } ;

dependent_writerがむンダむレクションを远加する無意味なレむダヌのように芋えるず決めおも驚くこずではありたせん。 dependent_writerを介しおアクセスするのではなく、「倉数」の倀を倉曎するラむタヌ<Tag>を盎接むンスタンス化しないのはなぜですか

事実、 ラむタヌ<int>ぞの盎接呌び出しは、関数テンプレヌトfの最初の匕数が2番目よりも早く評䟡されるこずを保蚌したせんそしお、関数は、最初の呌び出しでfalseを返す必芁があるこずを「蚘憶」し、その埌で「倉数」の倀を倉曎するだけです 。

必芁なテンプレヌト匕数を蚈算する順序を蚭定するには、dependent_writerを䜿甚しお远加の䟝存関係を远加できたす。 最初のdependent_writerテンプレヌト匕数は、むンスタンス化される前に評䟡される必芁があるため、 ラむタヌがむンスタンス化される前に評䟡する必芁がありたす。 したがっお、 Bをdependent_writerに匕数ずしお枡すず、 ラむタヌがむンスタンス化されるたでに、 fによっお返される倀がすでに蚈算されおいるこずを確認できたす。

泚実装を䜜成する際に、倚くの代替案を怜蚎し、最も簡単に理解できるものを芋぀けようずしたした。 この断片があたりにも混乱しないこずを心から願っおいたす。

魔法


テンプレヌト <
bool B = noexcept  flag  0   、 //1
int = sizeof  dependent_writer < B >  //2
>
constexpr int f  
{
リタヌン B ;
}

このスニペットは少し奇劙に芋えるかもしれたせんが、実際には非垞に簡単です


動䜜は、次の擬䌌コヌドで衚珟できたす。

 [ `int flag (int)`    ]:  `B` = `false`  `dependent_writer <false>`  `B` :  `B` = `true`  `dependent_writer <true>`  `B` 

したがっお、最初にfが呌び出されるず、テンプレヌト匕数Bはfalseになりたすが、 fを呌び出す副䜜甚は「倉数」 フラグの状態の倉化になりたすその定矩を生成しおbody mainの前に配眮したす。 さらにfを呌び出すず、 「倉数」 フラグはすでに「定矩枈み」状態になっおいるため、 Bはtrueになりたす 。


おわりに


C ++以前は䞍可胜ず考えられおいたで新しいこずを行うためのクレむゞヌな方法を人々が発芋し続けおいるずいう事実は、驚くべきものであり、ひどいものです。 - モヌリス・ボス

この蚘事では、定数匏に状態を远加する基本的な考え方に぀いお説明したす。 蚀い換えれば、定数衚珟は「定数」であるずいう䞀般に受け入れられおいる理論私がよく参照したは、今では砎壊されおいたす。

ご泚意 trans私の意芋では、「砎壊された」ずいう蚀葉は非垞に匷力です。 同じように、名前の同䞀性にもかかわらず、テンプレヌト関数fの 2぀の異なる特殊化が゜リュヌションで呌び出され、それぞれが完党に「䞀定」です。 もちろん、これはアむデアの䞀般的な有甚性を損なうものではありたせん。

この蚘事を曞いおいるずき、テンプレヌトメタプログラミングの歎史ず、この蚀語を䜿甚するず、意図した以䞊のこずができるようになるのがどれほど奇劙かを考えずにはいられたせんでした。
次は

smetaず呌ばれる呜什型テンプレヌトメタプログラミング甚のラむブラリを䜜成し たした 。これは、今埌の蚘事で公開、説明、および議論されたす。 取り䞊げるトピックの䞭で


ご泚意 trans著者は、 smetaのリリヌスをキャンセルするこずを決めたず報告しおいたす。 この蚘事および埌続の蚘事には、その機胜のほずんどすべおが含たれおいるたたは含たれるため、読者が独自に機胜を実装するこず自䜓は、ささいなこずです。 たずえば、私はすでにPhilipの譊告に反しおいく぀かのアむデアを玹介しおおり、将来それらをラむブラリのようなものに集める぀もりです。


アプリ


clangのこの および関連するバグのため、䞊蚘の゜リュヌションでは、正しく実装されおいる堎合、プログラムが正しく動䜜したせん。 以䞋は、 clang向けに特別に䜜成された゜リュヌションの代替実装ですこれはただ有効なC ++コヌドであり、どのコンパむラでも䜿甚できたすが、倚少耇雑です。

名前空間の詳现
{
構造䜓 A
{
constexpr A   { }
友達 constexpr int adl_flag  A  ;
} ;

テンプレヌト < typenameタグ>
構造ラむタヌ
{
friend constexpr int adl_flag タグ
{
0を 返し たす 。
}
} ;
}

template < typename Tag 、 int = adl_flag  Tag { }  >
constexpr bool is_flag_usable  int 
{
trueを返したす。
}

テンプレヌト < typenameタグ>
constexpr bool is_flag_usable  ... 
{
falseを返したす。
}

テンプレヌト < bool B 、 クラス Tag = detail :: A >
struct dependent_writer  detail :: writer <タグ> { } ;

テンプレヌト <
class Tag = detail :: A 、
bool B = is_flag_usable <タグ>  0  、
int = sizeof  dependent_writer < B > 
>
constexpr int f  
{
リタヌン B ;
}

int main  
{
constexpr int a = f   ;
constexpr int b = f   ;

static_assert  a = b 、 "fail"  ;
}

泚珟圚、この回避策がclangで効率的である理由を瀺す察応するバグレポヌトを曞いおいたす。 それらぞのリンクは、レポヌトが提出されるずすぐに远加されたすすべおが鈍い間- 箄Per。 。

元の蚘事の感謝セクション

謝蟞


この蚘事を曞かない人はたくさんいたすが、特に感謝しおいたす。

  • モヌリス・ボス
    • アむデアの策定を支揎したす。
    • コンタクトレンズを賌入するための資金を提䟛しおくれたので、盲目的に曞く必芁がなくなりたした。
    • 蚘事に察する圌の意芋に察する私の嫌がらせの蚱容。
  • マむケル・キルペラむネン
    • 蚌拠、およびこの蚘事をより理解しやすくする方法に関する興味深い考え。
  • コロンボ
    • 説明した手法が䞍正なプログラムを生成するこずを蚌明しようずしお倱敗した私の顔にC ++暙準の段萜を投げお。 どちらかずいえば、私は圌のために同じこずをしたす。


翻蚳者から


私はこの蚘事に玄1か月前に出くわし、テンプレヌトのメタプログラミングに機胜性、グロヌバル状態ぞの䟝存性を远加できるアむデアの恵みのひどいわいせ぀さに感銘を受けたした。 この蚘事の著者、 Philippe Rosenは、開発者、ミュヌゞシャン、ファッションモデルであり、良い人でしたが、芪切にロシア語に翻蚳するこずを蚱可しおくれたした。

この蚘事は、呜什型メタプログラミングに関する䞀連の蚘事の最初の蚘事であり、実際のメタプログラミングをはるかに䟿利にする構成を実装する前に、非定数constexprs 実際の即時適甚性は非垞に限られおいたすのアむデアを開発したす。

近い将来、残りの2぀の蚘事コンパむル時カりンタヌずメタタむプのコンテナヌに぀いおを翻蚳したす。 さらに、フィリップは、近い将来、シリヌズを継続し、さらにアむデアを発展させるず述べたしたもちろん、新しい翻蚳がありたす。

蚂正、远加、垌望は倧歓迎です。 フィリップ自身に手玙を曞くこずもできたす。圌はどんなコメントでも喜んでくれるず思いたす。

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


All Articles