なぜ「ディスアンビギュエータとしてテンプレート」を使用する必要

まず、なぜこのタイトルを行います

:ない力にロードされた、しかし、GCCの先端からこの文をこの問題のより本格的な登場シーンを表現するためのタイトルChinglish
のgcc-4.4.7 \ gccの\ CP \ parser.c
静的BOOL
cp_parser_optional_template_keyword(cp_parserパーサ*)
{
IF(cp_lexer_next_token_is_keyword(parser->レクサー、RID_TEMPLATE))
{
/ *テンプレートの`「キーワードのみ使用するテンプレート内とすることができる。
外テンプレートザ・パーサ図OUT CAN常に何IS A
テンプレートと* /何をされるわけではありません。
(!processing_template_decl)IF
{
cp_token * = cp_lexer_peek_tokenトークン(parser->レクサー)、
エラー( "%のH%<テンプレート%>(AS Aのディスアンビギュエータ)のみ許可されている"
テンプレート内で""、&token-> LOCATION);
/ *トークンストリームのこの部分がされている場合は再スキャン、同じ
エラーメッセージが生成されます。そこで、我々は、トークンをパージ
ストリームから。* /
cp_lexer_purge_token(parser->レクサー);
falseを返します。
}
...
}

この問題の理由を認識して第二に、

std :: tr1をの機能は主にタプルに基づいているため、彼らはタプルはオンライン、この問題を検索し、テンプレートのキーワードの説明を使用して、コールしばしば間違った時間の実現で見つかったの下でシミュレーション法を達成したいので、実現しています。なお、コードの下に
37のリターン<IDX + 1、typelistに ...> ::テンプレートを取得<T、インデックス>()tupleimp;
テンプレートキーワードを。

tsecer @ハリー:猫-n mytuple.cpp
1テンプレート<int型のx、型名... typelistに>構造体tupleimp。
2構造体callbase {}。
3構造体returnthis {}。
4
5テンプレート<ブールB>
6構造体は、選択した
7 {
8のtypedef callbaseタイプ;
9}。
10
11テンプレート<>
12構造体は、<真>選んだ
13 {
14のtypedef returnthisタイプ;
15}。
16
17テンプレート<整数X>
18の構造体tupleimp <X>
19 {
20}。
21
22テンプレート<INT IDX、型名HEAD、型名... typelistに>
23構造体tupleimp <IDX、HEAD、typelistに...>:公共tupleimp <IDX + 1、typelistに...>
24 {
25 tupleimp(ヘッドH、typelistに...引数):m_h(H)、tupleimp <IDX + 1、typelistに...>(引数...){}
26 HEADのm_h。
27
28テンプレート<型名T、INTインデックス>
29 Tのget(){
30型名が選択した<インデックス== IDX> ::型T。
31リターンフォーク<T、インデックス>(T)。
32}
33
34テンプレート<型名T、INTインデックス>
35 Tフォーク(callbase C){
36
37リターンtupleimp <IDX + 1、typelistに...> :: テンプレート取得<T、インデックス>();
38}
39
40テンプレート<型名T、INTインデックス>
41 Tフォーク(returnthis C){
42リターンm_h。
43}
44
45
46}。
47テンプレート<型名T>


50リターン0;
51}
52 INT X = FOO <整数>();
53テンプレート<型名... typelistに>
54構造体タプル:公共tupleimp <0、typelistに...>
55 {
56タプル(typelistに...引数):tupleimp <0、typelistに...>(引数...) {}
57}。
58
59テンプレート<整数インデックス、型名T、型名TUPLE>
60 T GET(TUPLE&T)
61 {
62リターンt.get <T、インデックス>();
63}
64
65タプル<フロート、文字、整数> TUP(.0、 'Z'、66);
66
67 INT()主
68 {
69リターンGET <2、整数>(TUP)。
70}
ハリー@ tsecer:G ++ -std = C ++ 11 mytuple.cpp
tsecer @ハリー:./a.out
tsecer @ハリー:エコー$?
66

第三に、より多くの古典的な問題のシーン:なぜ我々は、型名の文が必要なのですか

解決TYPEへのコンパイラ:: Tは、それは「構文属性」はい何であるかを知らない場合とき、C :: fooの機能で、以下の例を参照してください。例えば、A、TはBに、型であり、Tは可変である:それは識別子(識別子)またはタイプ(タイプ)である「属性構文」とは、いわゆる あなたは思うかもしれません:とにかく、それはタイプかの変数があることを明らかに状態に、このチェックはその後、リアルタイム型で提供され、なぜ必要性を確認しますか?それとも、構文上の特性を有するように、「構文木」、シンタックス要素の数を生成するために最初にされている解析するとき、このプロパティはパースと行動の意味論の実施を推進します強調しました。あなたがわからない属性構文であれば、それだけで字句単位だと言うことは、より直感的なコンパイルの意味を解決する必要はありません。
ハリーtsecer @:CAT -n why.disambigous.cpp
。1つの構造体A
2 {
3 int型T;
。; 4}
。5
。6 B構造体
。{7
。8のtypedef int型T、
9};
10
。11テンプレート<型名TYPE>
12 Cは構造体です
13は、{
ボイドFOO 14()
15 {
16 10 * T TYPE ::;
17 TYPE T * T ::;
18れる}
19};
ハリー@ tsecer:GCC -C why.disambigous.cpp LC_ALL = C
why.disambigous.cpp:内のメンバー関数'のボイドC <TYPE> :: FOO()':
why.disambigous.cpp :. 17:13です:エラー: 'T'はこのスコープで宣言されていない
TYPE :: T * T;
^
tsecer @ハリー:
注:タイプ:: T * 10があり;デフォルトで指定されていない場合で説明したエラーなしで、それが想定されている識別子(というよりタイプ)としてコンパイラ。

四、テンプレートIDを解析GCC

ここでの主なロジックは以下のとおりです。テンプレートを指定した場合、コンパイラの裏には名前とテンプレートますので、<引数リストを...>全体として組成物中にコンテンツ名及び角度かっこで全体のテンプレートID(テンプレートIDに解決さテンプレートID)。コンテンツは、ブラケットが消費この角度ここでない場合は逆に、時間の意志角括弧は、以下(<)より大きい(>)以上のように処理し、構文エラーが発生しています。
ツリー静的
cp_parser_template_id(cp_parser *パーサー、
BOOLのtemplate_keyword_p、
BOOLのcheck_dependency_p、
BOOLのis_declaration)
{
...
/ *解析ザ・テンプレート名* /
is_identifier = falseに、
トークン= cp_lexer_peek_token(parser->レクサー);
TEMPL = cp_parser_template_name(パーサー、 template_keyword_p、
check_dependency_p、
is_declaration、
&is_identifier);
IF(TEMPL == is_identifier error_mark_node ||)
{
pop_deferring_access_checks()。
TEMPLを返します。
}

......


{
/ * `<」テンプレート引数リストを開始するためのルック。* /
IF(cp_parser_require(パーサ、!CPP_LESS、 "%<<%>"))
{
pop_deferring_access_checks();
error_mark_nodeを返します。
}
/ *引数を解析します。* /
引数= cp_parser_enclosed_template_argument_list(パーサ)。
}

......

/ *暫定的に解析する場合は、作る一連のトークン置き換え
CPP_TEMPLATE_IDトークンでテンプレートIDをアップします。そうすれば、
私たちはトークンストリームを再解析する必要があり、我々は繰り返す必要はありません
解析を行うために必要な努力を、また我々は、重複発行されます
のインスタンス化中の問題に関するエラーメッセージを
テンプレート。* /
IF(start_of_id)
{
cp_token *トークン= cp_lexer_token_at(parser->レクサー、start_of_id)。

/ * START_OF_IDトークンの内容をリセットします。* /
token->タイプ= CPP_TEMPLATE_ID。
/ *任意の繰延チェックを取得します。まだこのアクセスチェックをポップしない
メモリは、トークンは、以下の交換の際に再利用されないようにします。* /
token-> u.tree_check_value = GGC_CNEW(構造体tree_check)。
token-> u.tree_check_value->値= TEMPLATE_ID。
token-> u.tree_check_value->チェック= get_deferred_access_checks()。
token->キーワード= RID_MAX。

/ *パージ後続のすべてのトークン。* /
cp_lexer_purge_tokens_after(parser->レクサー、start_of_id)。

/ * ??? 私たちは、実際にTEMPLATE_ID ==場合は、以下のことを想定することができ
error_mark_node、我々はに診断発行しているだろう
と単純に仮の解析をマーキングとは対照的に、ユーザーは、
失敗しましたか?* /
(cp_parser_error_occurred(パーサ)&& TEMPLATE_ID = error_mark_node!)もし
エラー( "テンプレート引数リストの%Hparseエラー"、
&token->場所)。
}

......

}

五、C ++の問題の仕様記述

下面(テンプレートの特殊一节の14.2名)例中说明了模板的左尖括号会被当做小于号
メンバーテンプレートの特殊化の名前が後に表示された場合。あるいは- >後置式にまたは後
修飾-IDでネストされた名指定子、および後置式かのオブジェクトまたはポインタ表現
資格-IDでネストされた名指定子は、テンプレートパラメータに依存します(14.6.2)だけに言及していない
現在のインスタンス化(14.6.2.1)のメンバー、メンバーテンプレート名は、キーワードを前置する必要があります
テンプレート。それ以外の場合は名前が非テンプレートに名前を付けると想定されます[例:
構造体のX {
テンプレート<はstd :: size_tの> X * ALLOC()。
テンプレート<はstd :: size_tの>静的X *調整();
}。
テンプレート<クラスT>ボイドF(T * P){
T * P1 = P-> ALLOC <200>(); //悪い形成<手段未満
T * P2 = P->テンプレートALLOC <200>(); // OK:<テンプレート引数リストの始まり
Tを:: <100>()を調整します。// 悪い形成<手段未満
T ::テンプレートは<100>()を調整します。// OK:<テンプレート引数リストを開始
}
末端の一例]

6つの例

以下のコードのための
テンプレート<型名T>
構造体A
{
int型のfoo()
{
リターンバーテンプレートT :: <整数>()
+ T ::バズ<T :: BZZ>();
}
};

解決名に1、

cp_parser_qualifying_entity == >> cp_parser_class_name == >> cp_parser_template_id == >> cp_parser_template_name
Tを解析する::テンプレートバー<整数>( ) 、から関数

IF(スタート)
cp_lexer_purge_tokens_after(parser->レクサー、[スタート]);
IF( is_identifier)
* = trueにis_identifier、
折り返し識別子;

ここに戻って。
T ::バズ<T :: bzz>行う場合 )( 、ノーリターンが存在しない場合、以下、ヌルにノードリターンに進みます。
ツリー静的
cp_parser_template_name(cp_parser *パーサー、
BOOLのtemplate_keyword_p、
BOOLのcheck_dependency_p、
BOOLのis_declaration、
BOOL * is_identifier)
{
ツリー識別子、
ツリー赤緯、
ツリーFNS;
cp_token * = cp_lexer_peek_tokenトークン(parser->レクサー)。

/ *次のトークンが`演算子」であれば、私たちはどちらか持っている
オペレータ機能-IDや変換機能-IDを。* /
IF(cp_lexer_next_token_is_keyword(parser->レクサー、RID_OPERATOR))
{
/ *私たちは、私たちが見ているかどうかわからない
オペレータ機能-IDや変換機能-ID。* /
cp_parser_parse_tentatively(パーサ)。
/ *オペレータ機能-IDをお試しください。* /
識別子= cp_parser_operator_function_id(パーサ)。
/ *それが機能しなかった場合は、変換機能-IDを試してみてください。* /
IF(cp_parser_parse_definitely(パーサ)!)
{
cp_parser_error(パーサ、 "期待されるテンプレート名");
error_mark_nodeを返します。
}
}
/ *識別子を探します。* /

識別子= cp_parser_identifier(パーサ)。

/ *我々は、識別子が見つからなかった場合、我々はテンプレートIDを持っていません。* /
IF(識別子== error_mark_node)
戻りerror_mark_node。

名前はすぐに`テンプレート」キーワードに従った場合は/ *、それは
テンプレート名です。次のトークンがない場合は、 `<」の場合、
それが使用されていないので、我々は、テンプレート名としてそれを扱わない
テンプレート-IDの一部として。これは、構造を処理することを可能に
ように:

テンプレート<型名T>構造体S {S(); }。
テンプレート<型名T> S <T> :: S();

正しく。「 -それは`S <T>であれば、テンプレートとして」私たちは` Sを扱っていました
-しかし、何の`<」が存在しない場合は、私たちにはありません。* /

IF(processing_template_decl
&& cp_parser_nth_token_starts_template_argument_list_p(パーサ、1))
{
/ *宣言において、依存文脈において、我々はふり
「テンプレート」キーワードはエラー向上させるために存在していた
回復を。例えば、与えられました:

テンプレート<型名T>のボイドF(T :: X <整数>);

私たちは、テンプレートIDとして「X <整数>」扱いたいです。* /
もし(is_declaration
&&!template_keyword_p
&& parser->スコープ&& TYPE_P(parser->スコープ)
&& check_dependency_p
&& dependent_scope_p(parser->スコープ)
、彼らは決して以来/ * Doが、dtors(またはctors)のためにこれをしない
テンプレートを必要としません。自分の名前の前にキーワード* /
!&& constructor_name_p(識別子、parser->スコープ))
{
cp_token_position開始= 0;

/ *何が悪かったのか説明してください。* /
エラー( "%Hnonテンプレート%を鋳型としてQD"、
&token->位置、識別子)。
(input_location、 "使用%<%T ::テンプレート%D%>それがテンプレートであることを示すために"、通知
parser->スコープ識別子)。
/ *暫定的に解析する場合は、「<」トークンの場所を見つけます。* /
(cp_parser_simulate_error(パーサ))場合に
開始= cp_lexer_token_position(parser->レクサー、TRUE)。
/ *我々は、エラーを発行することができるようにテンプレート引数を解析し
、それらについてのメッセージを。* /
cp_lexer_consume_token(parser->レクサー);
cp_parser_enclosed_template_argument_list(パーサ)。
/ *スキップは、私たちがするから良い場所を見つけるまで、トークン
解析を継続します。* /
cp_parser_skip_to_closing_parenthesis(パーサ、
/ * = * /真、回復
/ * or_comma = * /真、
/ * consume_paren = * / false)を;
/ *暫定的に解析する場合は、恒久的に削除
テンプレート引数リストを。それは重複しなくなり
行方不明について発行されてからのエラーメッセージを
「テンプレート」のキーワード。* /
IF(スタート)
cp_lexer_purge_tokens_after(parser->レクサー、開始)。
(is_identifier)の場合
* is_identifier =はtrue。
識別子を返します。
}

「テンプレート」のキーワードが存在する場合/ *、その後、一般的にはありません
、我々はただの識別子を返すように、何のポイントは、名前のルックアップを行うことに。
しかし、予選スコープが非依存であるならば、我々はできる
(および必要があります)通常は名前ルックアップを行います。* /
IF(template_keyword_p
&&(parser->スコープ!
||(TYPE_P(parser->スコープ)
&& dependent_type_p(parser->スコープ))))
折り返し識別子。
}

/ *名前を検索します。* /
赤緯= cp_parser_lookup_name(パーサ、識別子、
none_type、
/ * is_template = * /偽、
/ * is_namespace = * /偽、
check_dependency_p、
/ * ambiguous_decls = * / NULL、
token->位置)
赤緯= maybe_get_template_decl_from_type_decl(赤緯)。

DECLがテンプレートである場合は/ *、その名前は、テンプレートの名前でした。* /
IF(TREE_CODE(供述)== TEMPLATE_DECL)

他に
{
ツリーは、fn = NULL_TREE。

/ *標準を明示的に示していないことを名前か
名前であるそのうちのいくつかはオーバーロードされた宣言、一連の
テンプレートは、テンプレートの名前です。しかし、そのような名前がなければならない
テンプレート名で。それ以外の場合は、形成する方法はありません
オーバーロードされたテンプレートのテンプレートIDを。* /
FNS = BASELINK_P(供述)?BASELINK_FUNCTIONS(赤緯):供述。
IF(TREE_CODE(FNS)== OVERLOAD)
用(FN = FNS; FN; FN = OVL_NEXT(FN))
(TREE_CODE(OVL_CURRENT(FN))== TEMPLATE_DECL)場合
ブレーク。

もし(!は、fn)
{
/ *名前は、テンプレートに名前を付けていません。* /
cp_parser_error(パーサ、 "期待されるテンプレート名");
error_mark_nodeを返します。
}
}

/ * DECLが依存しており、機能を参照している場合は、単に返す
その名前を。私たちは、テンプレートのインスタンス化の際に再びそれを見ていきます。* /
IF(DECL_FUNCTION_TEMPLATE_P(赤緯)|| DECL_P(赤緯)!)
{
ツリースコープ= CP_DECL_CONTEXT(get_first_fn(赤緯))。
IF(TYPE_P(スコープ)&& dependent_type_p(範囲))
リターン識別子。
}

赤緯返します。
}

テンプレートがない場合2は、続行する方法へと識別されます

解析時、T ::バズ<T :: bzzバイナリ(build_x_binary_op関数発生器)「未満」は、新しい中間結果およびそれに続くまで来ると同定「>工程()」、この場合に「>」の識別番号よりも小さく、通常は正規表現でなければならないの後、例えば、(1 + 2)、又は(INT)0.1 / 0.01とすることができます。
T ::バズ<T :: bzz> ();
以下の形式を使用している場合、したがって、コンパイラはさえ与えられない
ハリー@ tsecer:CAT -n template.keyword.cppを
1テンプレート<型名T>
2 A構造体
3 {。
int型のFOO 4()
5 {
6 ::バズリターンT <T :: BZZ>(1 + 2);
7}
8};
ハリー@ tsecer:GCC -C template.keyword.cpp
tsecer @ハリー。

数およびARG1 ARG2のgccの表示に関する未満の値を見ることができ、それらは本当に単純な識別子と考えられています

<scope_ref 0x7ffff0c80780
引数0 <template_type_parm 0x7ffff0c8d900 T type_0 type_6 VOID
ALIGN 8 SYMTAB 0別名セット-1標準型0x7ffff0c8d900
インデックス0レベル1 orig_level 1つの
鎖<type_decl 0x7ffff0c8d9c0 T >>
引数1 <identifier_node 0x7ffff0c96a20 bzz
バインディング<(NIL)>
ローカルバインディング<(NIL)>>>

 

<scope_ref 0x7ffff0c806c0
引数0 <template_type_parm 0x7ffff0c8d900 T type_0 type_6 VOID
ALIGN 8 SYMTAB 0別名セット-1標準型0x7ffff0c8d900
インデックス0レベル1 orig_level 1つの
鎖<type_decl 0x7ffff0c8d9c0 T >>
引数1 <identifier_node 0x7ffff0c969c0バズ
バインディング<(NIL)>
ローカルバインディング<(NIL)>>>

 

おすすめ

転載: www.cnblogs.com/tsecer/p/12584169.html