
- C++からDへの移植
[D]
このページは、PortingFromCxx からの翻訳です。
ファイルが存在しません。
C++からDへの移植
D言語はC++よりも優れています。少なくともC++よりも優れたものにすることがウォルターの主要なモチベーションでした。ですので、C++のコードをD言語に移植することに特に興味をもつことは意味のあることです。このページは移植のための様々な利用可能な方法、その上で出てきた問題、そしてワークアラウンドについて議論しています。
移植すべきか、ラップすべきか?
D言語は、C言語とは違い直接C++のコードを呼び出すことはできません。それ故、D言語が呼び出すことのできるC APIの中にC++のコードをラップするか、C++のコード1行1行すべてをネイティブなD言語のコードに翻訳する必要があります。
- 移植
- ○ - 成果物は100% D言語であり、D言語からビルドと利用が簡単にできる
- ○ - 将来の開発でC++から独立したものになるだろう
- × - 労力がかかるだろう
- × - C++の元々のライブラリのコードの変更に追随することは難しくなるだろう
- ラッピング
- ○ - そこまで労力はかからないだろう
- ○ - C++の上流の変更に追随しやすくなる
- × - 成果物は混合物となり、C++コードのビルドを事前に要求するものになるだろう
- × - 帰納的に何かが消えてしまう(templateはC APIでラップするのが難しい)
このページは実際にC++を移植している。ラッピングする場合はC++のラッピングのページを見よ。
問題の概観
この章ではD言語への移植時にあなたが躓くであろうC++コードのことについて短めの説明をしています。この章はなんの解決策も提供しません、ただ問題を紹介するだけです。
- コンストラクタ
- D言語とC++は少しばかり見た目と振る舞いが異なっています
- Class vs Struct
- C++内ではそれらは実際同じものです。ですのでD言語への翻訳時にあなたがどちらを用いるべきかについては決定することが難しい。
- Struct の継承
- C++の構造体は他の構造体から継承できます。なので、クラスや値として使用されている構造体を使用するC++のコードは移植しにくくなりそうです。
- 多重継承
- C++は多重継承を使用することがありますが、Dはその代わりにインターフェースを使用します。
- マクロ
- C++は邪悪で本当にトリッキーなC++のマクロを使用できます。
- 参照渡しの返り値
- C++の関数は参照を返すことができます。
- Const
- C++はconstをもちます。
- friend
- C++のfriendキーワードは望んだクラスへのプライベートレベルでのアクセスを許容します。
- イテレータ
- イテレータはC++で一般的に使用される。しかし、その一般的なイディオムはD言語が提供しない演算子のオーバーロードに依存している。さらに、foreach/opApplyといった正しいD言語のアプローチとどうやって統合するかという問題がある。
- スマートポインタ
- 演算子のオーバーロードを使用することで、明示的なデストラクタ、そしてコピーコンストラクタ、が使用できます。C++は参照をカウントするメモリー管理のようなことをスマートポインタで実装可能です。D言語ではそれは不可能です。
- templateの特殊化
- C++は異なるソースファイルに現れるtemplateの特殊化を許容します。C++はまた、IFTIによって選択された特殊化を許容します、これはD言語内でトラブルのもとになっている。
- 名前空間
- C++は名前空間をどこでも好きなように作成可能だ。それらはどのみちヘッダーファイルの中では内部的にリンクされない。ですが、良きC++のコードはたいてい1ヘッダーファイルに単一の名前空間を作るという原則に従っているはずです。
- IOStreams
- phobosもTangoもほとんどの場合はC++のiostreamに対抗できるストリームベースの入出力機構をもっています。しかしストリーミングオブジェクトに使われがちなイディオムである、ヘッダーファイル内に 'write_object(ostream&,MyObject&) のような特定の関数をオーバーロードするようなものをおくこと。これをD言語に移植する際は、D言語に欠けている argument-dependent lookup (ADL) の問題にぶつかることになるでしょう。
- STL
- C++のコードはSTLのコンテナを多用します。いくつかはD言語でも対応するものが使用できますが、できないものもあります。
- 演算子のオーバーロード
- すべての演算子のオーバーロードはC++の形式から翻訳すべきでしょう。operator hogeはよりD言語チックなopHogeに。しかしすべてのC++の演算子はDと互換性があるわけではありません。C++は独立した比較演算子のオーバーロードさえ許容します。参照外し演算子(operator *)、メンバーアクセス演算子(operator ->)、そしてキャスト演算子(operator float() など)
- 暗黙の型変換
- C++は暗黙的なキャストを定義できます、それは例えば class 'C' が 'float'として扱われるようにするなどです。
- 非メンバー変数の演算子のオーバーロード
- C++はユーザ定義の演算子のオーバーロードをクラス外でも許容します
- String vs char
- D言語は多くの文字列の型をもちます、そしてC++も同じようにいろいろあります。
標準的な移植の提案
基礎工事から始めよ
ユニットテストを書こう
詳細な移植方法の提案
簡単な機械的変換のたぐい
移植作業のうちの多くが機械的な変換で行われています。翻訳の取り組む際の最初の一歩としては…
- foo.cppをそれと関連するヘッダ、foo.hppとマージする
- すべての#includeをimportに変換する
- -> から . への変換
- :: から . への変換
- typedef から alias への変換
- const から /*const*/ への変換 (もしくは単に削除する、しかしそれを置いておけばソースコードの意図を伝えるドキュメントになりますし、将来的にconstが実装されたD2への移植の助けになる)
- すべてのインラインキーワード( inline, __inline, __forceinline)を削除する
- すべてのクラスのコンストラクタを ClassName() から this() に変更し、デストラクタは ~this() に変更する
- すべての参照渡しを含む関数 Foo& x を ref Foo x に変更する
- すべてのtemplate宣言 template<typename T> symbol および template<class T> symbol を symbol(T)に変更する、シンボルが関数名を現す場合、 class classname もしくは struct structname とする
- templatename<T>をtemplatename!(T)のようなテンプレートの宣言に置換する
- dynamic_cast<T>をcast(T)に置換する
- reinterpret_cast<T>をcast(T)cast(void*)に置換する
- var == NULL や var != NULL は var is null と var !is nullに置換する
- D言語において、等号(
と !=)と恒等式(is と !is)は2つの分割された演算となる。等号はopEqualsの演算子オーバーロードによってオーバーロードできる。もし、" varnull "とvarが本当にnullであることを試行しようとした場合、varの中でopEqualsメソッドを探そうとしたことによるアクセス違反が起こるでしょう。恒等式はオーバーロードできない。恒等式はクラスの参照、配列の参照(そこでは、2つの参照が同じポインターと長さを保持しているかどうかをチェックする)、そしてポインターに使用される。それは実際どのような型にも使用されうる、つまり非参照型、恒等式は等号と同じものである。
- D言語において、等号(
- 関数の先行宣言を削除する。
- 管理人追加
変更前 | 変更後 | sedのコマンド | 備考 |
---|---|---|---|
#include <stdio.h> | import std.stdio; | sed -e 's/#include/import/g' | 特になし |
-> | . | sed -e 's/->/\./g' | アロー演算子はなくなった |
コンストラクタ
もしかすると、単に例示をすることがもっとも簡単なかもしれません。あなたがC++とDを適度に知っていれば何をしようとしているかは明確でしょう。
- C++
class MyClass : public BaseClass { public: int inum_; float fnum_; char[] str_; MyClass(int inum, int fnum, int str) : BaseClass(str), inum_(inum),fnum_(fnum),str_(str) { /* extra statements */ } }
- D言語のクラスで
class MyClass : BaseClass { int inum_; float fnum_; char[] str_; this(int inum, int fnum, int str) { super(str); inum_ = inum; fnum_ = fnum; str_ = str; /* extra statements */ } }
- D言語の構造体で(C++には基底クラスがないものと想定します)
struct MyClass { int inum_; float fnum_; char[] str_; static MyClass opCall(int inum, int fnum, int str) { MyClass ret; with (ret) { inum_ = inum; fnum_ = fnum; str_ = str; /* extra statements */ } return ret; } }
Class vs Struct
C++ の仮想関数 / D のoverride
Struct の継承
多重継承
マクロ
参照渡しの返り値
一般的な参照
Const
friend
D言語では同じモジュールのメンバーは暗黙的にfriendレベルでのアクセス扱いになります。なので、単純な解決策は同じモジュールの中に関連するクラスを置くことです。
イテレータ
スマートポインタ
templateの特殊化
名前空間
IOStreams
STL
演算子のオーバーロード
暗黙の型変換
非メンバー変数の演算子のオーバーロード
String and Char
Windows固有の問題
Posix固有の問題
ツール類
C言語からC++に移植するために同様のツールが存在する。
- htod - C言語のコードを操作することができるWalter Brightのツール -- 本当はC++向けのツールではない。
- BCD - Gregor Richardのgcc-xmlベースの翻訳ツール、これはC++のサブセットを操作できる。
- SWIG - SWIGはいろいろなプログラム言語を使ってC/C++で書かれたプログラムを接続するためのソフトウェア開発ツールです。SWIGはD1とD2をサポートします。今のところ、あなたはSWIGをSVNからビルドする必要がある。SWIG 2.02は公式なDのサポートを得ている。