2010-12-31 13 views
-2

私はC++でさまざまなデータ型を生成したいと思います。たとえば:ユニークな合成名

struct struct_int_double { int mem0; double mem1; }; 

現時点で私のコンパイラは、異なる翻訳単位で同じデータ型をコンパイルするときに名前が一致しないことカウンタを使用して、名前を合成します。

は、ここでは動作しません何:ABIのmangled_name機能を使用して

  1. 。一意の名前を持つ構造体にはすでに依存しているからです。構造体を匿名で偽装してC++ 11準拠のABIで動作する可能性がありますか?

  2. テンプレート(例:テンプレートは再帰型では機能しないため、struct2)

  3. 完全なマングリング。それはその後、私は考えることができる唯一のことは、最初のユニークな長いマングル名を作成することですあまりにも長い間されている名前(文字の数百!)別にグローバルレジストリ(YUK!)から

を与え、そしてのでそれを短縮するためにダイジェストまたはハッシュ関数を使用します(そして、衝突がないことを望みます)。

実際の問題:型が匿名である場所、たとえばタプル、合計型、関数型などと呼ばれるライブラリを生成する。

他のアイデアはありますか?

EDIT:再帰型問題の追加説明。

template<class T> 
typedef pair<list<T>*, T> list; 

これは実際に必要なものです。これは2つの理由から機能しません。まず、typedefをテンプレート化できません。 [いいえ、あなたはtypedefでテンプレートクラスを使うことはできません。それはうまくいきません]次に、リスト*がまだ定義されていないので引数として渡すことができません。多型を持たないCでは、あなたはそれを行うことができます:

struct list_int { struct list_int *next; int value; }; 

いくつかの回避策があります。このの場合、特にの問題では、Barton-Nackmanの変種を使うことができますが、それは一般化しません。

一般的な回避策があります.Gabrielle des Roisが最初に私に示したのは、開いた再帰を伴うテンプレートを使用し、それを閉じるための部分的な特殊化です。しかし、これは生成するのが非常に難しく、たとえそれを行う方法を見つけ出すことができても、おそらく判読できないでしょう。

バリアントも正しく処理するのに問題がありますが、それは直接関係しません(構築可能な型を持つ構造体を宣言することに対する愚かな制限のために悪化します)。

したがって、私のコンパイラは単純に通常のC型を使用します。それは多様性をとにかく扱わなければなりません:それを書く理由の1つは、テンプレートを含むC++型システムの問題を回避することでした。これにより、命名の問題が発生します。

+3

'std :: tuple'の何が問題なのですか? (または 'std :: tr1 :: tuple')実際にここで何を達成しようとしていますか? –

+1

'.memN'の代わりに' .get () 'の何が問題になっていますか? –

+0

@Billy:std :: tupleのようなものはありません(とにかくC++ 98で)。 C++ 11がこれを持っていて、それがテンプレートだと(テンプレートは再帰型を扱うことができません)、OSXの現在のg ++​​がC++ 11のサポートをあまり持っていないので、私はそれを使いたくないです(残念です)。 – Yttrill

答えて

1

実際に名前を一致させる必要がありますか?さまざまな名前の別々の構造体を異なる翻訳単位で定義し、C++コンパイラを幸せに保つために必要な場合はreinterpret_cast<>を定義するだけです。もちろん、手書きのコードでは恐ろしいでしょうが、これはコンパイラによって生成されたコードなので、C++コードが生成される前に必要な静的型チェックを実行できます。

私が何かを見逃していて、実際に同意するには型名が必要な場合は、すでにあなた自身の質問に答えていると思います。コンパイラが複数の翻訳単位の翻訳(いくつかのグローバルレジストリ)私は、ネームマングリングの明白な1つを除いて、型の構造型から一意の決定論的な名前を生成する方法を見ることができません。

名前の長さについては、なぜ重要なのか分かりません。名前を短縮するためにハッシュ関数を使用することを検討している場合は、人間が読めるようにする必要はないので、なぜそれらを短くする必要がありますか?

個人的には、おそらく半人が読める名前を、既存のネームマングリングスキームと同様のスタイルで生成し、ハッシュ関数を気にしないでしょう。したがって、struct_int_doubleを生成する代わりに、sid(struct、int、double)またはsi32f64(struct、32ビット整数、64ビット浮動小数点数)などを生成することがあります。そのような名前には、そのまま解析することができるという利点があります(デバッグにはかなり必要なようです)。

編集

いくつかのより多くの思考:

  • テンプレート:私はそれが可能であったとしても、この問題を回避するためにテンプレートコードを生成する際に任意の本当の利点が表示されません。リンカにシンボル名の長さの制限があることを心配している場合、リンカにはテンプレートの概念がないため、テンプレートは助けになりません:表示されるシンボルはC++コンパイラによって生成されたテンプレート構造の変形されたフォームになります。 felixコンパイラによって直接生成された長い名前のmangledとまったく同じ問題があります。
  • フェリックスコードで指定されたタイプは、生成されたC++コードにそのまま保持され、直接使用されるべきです。私は匿名の型の複雑さに実用的な(柔らかい)可読性/保守性の制約があると思うでしょう。名前を生成するために必要な唯一のものです。私は、あなたの "変種"は弁別された共用体であると仮定しているので、各構成要素の部分はフェリックスコードで定義された名前(タグ)を持たなければなりません。 (私はこのコメントに言及しましたが、私は答えを編集しているので、それを含めることもできます)
  • マンガの名前の長さを短縮する:ハッシュ関数を使って長い名前のmangledを実行するのが最も簡単な方法です。良いハッシュ関数を使用し、ハッシュ名に十分なビット数を保持する限り(ハッシュ名をエンコードするアルファベットは37文字なので、完全な160ビットのsha1ハッシュを書くことができる限り、衝突の可能性は許容されるはずです)約31文字)。ハッシュ関数の考え方は、ハッシュされた名前から元の名前に直接戻ることができないことを意味しますが、決して行う必要はありません。そして、私が推測するコンパイルプロセスの一部として、補助名マッピングテーブルをダンプすることができます(あるいは、おそらくCの構造体定義から名前を再生成します)。あるいは、まだ実際にハッシュ関数が気に入らなければ、合理的にコンパクトなビットレベルのエンコーディングを定義して(それを37文字の識別子のアルファベットに書き込む)、またはそのビットレベルで汎用の圧縮アルゴリズムを実行することもできますエンコーディング。分析するのに十分なフェリックスコードがあれば、固定圧縮辞書をあらかじめ生成することもできます。それは当然のことながら猛烈な嫌がらせです。ハッシュを使うだけです。

編集2:申し訳ありませんが、脳障害 - SHA-1ダイジェストが160ビットではなく、128


PSです。なぜこの質問がダウン投票されたのか分かりません。私にとっては合理的ですが、あなたが取り組んでいるこのコンパイラに関するいくつかの文脈が助けになるかもしれません。

+0

@ジョン:人々は私のトーンが技術的な内容ではなく好きではないのでおそらく投票しました:)コンパイラへのポインタが必要ならば:http://felix-lang.org。スクリプト言語よりも使いやすく、はるかに安全な、超高速のコードを生成します(多くの場合CまたはC++より高速です)。 – Yttrill

+0

@ジョン:現在、私はプログラマが名前を指定させることによって、この問題を関数で "解決"しています。関数の場合:fの(int)を "f"としてエクスポートします。文は、ネイティブ関数fに対して "f"という名前のCラッパーを作成します。それはOKですが、fを呼び出すために必要な型はどうですか?だから、私はユーザーに "int_double"としてint型* doubleをエクスポートすると、これはtypedefを作成します。 extern "C"関数はマングルされていないので、ここでの外部リンケージは問題になりません。問題は、型に他の型を含めることができ、ツリー全体に名前を付ける必要があることです。 – Yttrill

+0

@ John:名前の長さは、(a)C++コードをデバッグする必要があり、したがって(b)リンカの名前の長さに制限があるためです。シンプルな名前の場合、 "sid"は問題ありません。しかし、バリアントには、それぞれ4つの型を持つタプル引数を持つ100個のケースが含まれていることがあります。したがって、数千文字になる400個のコンポーネントを指定する必要があります。 – Yttrill

0

私は本当にあなたの問題を理解していません。

template<typename T> 
struct SListItem 
{ 
    SListItem* m_prev; 
    SListItem* m_next; 
    T m_value; 
}; 

int main() 
{ 
    SListItem<int> sListItem; 
} 
+0

そうですね、あなたはその問題を理解していません。問題は、コンビネータのみを使用して型を構築することです。クラスを定義することはできません。コンビネータと固定セットのプリミティブを使用することのみが許可されています。結合子は:tuple <>、variant <>、ポインタ<>、関数<>です。 – Yttrill

+0

リストは次のように定義されています:リスト =変種< tuple<>、タプル<ポインタ< list >>>これはFelixで "(1 + T * U)as U"と書くことができます。ここで、 "ポインタ"ビットは落とされ、 "U"は定義なしで再帰を導入します:これは基本的に型理論式ですが、与えられたものは同じです。 – Yttrill

+0

はい、あなたはフェリックスでそれを文字通り行うことができ、OcamlとHaskellのそれに近いことができます。 – Yttrill

関連する問題