出力用シフト演算子(<<)のオーバーロード
C++ の標準ライブラリでは cout などにシフト演算子(<<)を使って出力します。
std::cout << "Hello World!!" << std::endl;
これは iostream の上位クラスである ostream のシフト演算子(<<)のオーバーロードで実現されているのですが、これを自分で定義したクラス、構造体、列挙型などに対しても定義しておくと便利です。
これを定義しておくだけで、標準出力(cout), ファイル(ofstream), 文字列(stringstream)などにも自分で作ったクラス等を文字列として出力することが出来ます。
どうやるかというと、例えば点の構造体 Point があったとすると以下のように ostream クラスとシフト演算子(<<)の 2 項演算をオーバーロードします。
std::ostream &operator<<(std::ostream &out, const Point &tgt)
{
out << "(" << tgt.x << "," << tgt.y << ")";
return out;
}
この定義はクラス(構造体)定義の外で行うので、列挙型も定義できます。
ただし、クラスの場合は外なのでゲッターなどを用意しておく必要があります。
さらに以下のようなテンプレート関数を用意しておけば、簡単に文字列に変更できます。
template <typename T_t>
std::string to_str(const T_t &val)
{
std::stringstream ss;
ss << val;
return ss.str();
}
この関数は int 基本型を含めた ostream のシフト演算子(<<)をオーバーロードしているものであれば何でも文字列に変換できます。
to_str(5); // "5"
to_str(Point(2, 3)); // "(2, 3)"
ちなみに入力用のシフト演算子(>>)を使えば 値 → 文字列 変換の from_str() のような関数も作れます。ただし、入力用の場合は変換できなかった場合の例外処理も必要になってきます。
実は Boost ではこの to_str()、 from_str() のような関数をもっと一般的にした lexical_castというのが用意されているので、 Boost 使えばすぐ使えるようになります。
Qt の場合だとこのようなテンプレートを使った変換は残念ながら用意されていないのですが、 Qt で用意されているクラスはほとんど QDebug というデバッグ用の出力先への演算子がオーバーロードされているので、何も定義しなくてもダンプだけならできます。
qDebug() << QPoint(2, 3); // "QPoint(2, 3)"
VS のビルドをコマンドラインで実行する
コマンドラインでビルドできるとバッチファイルなどのスクリプトで実行できるようになりますし、 Emacs 上からビルドもできるようになります。 Emacs 上でコンパイルする設定は以前少し書きました。
http://yohshiy.blog.fc2.com/blog-entry-10.html
私は Un*x 系での開発の場合は、編集、ビルド、デバッグとすべて Emacs 上からやるのですが、 Windows の開発でも 編集、ビルドまで Emacs 上でできます。デバッグだけはコマンドライン上からできないので、おとなしく Visual Studio でやってます。
MSBuild
ビルドをコマンドライン上からやるには MSBuild というプログラムを使用します。これは .NET ランタイムと一緒に配布されているもので通常以下の場所にインストールされています。
c:/Windows/Microsoft.NET/Framework/vX.X
ここに PATH を通せば、 MSBuild で呼び出せます。
使用法は以下の形式です。
$ MSBuild [プロジェクトファイル]
*.vcxproj(VS2010)、 *.vcproj のようなプロジェクトファイルだけでなく、*.sln のソリューションファイルもビルドできます。省略した場合はカレントフォルダにあるものを探して実行します。
オプションを指定していない場合はデフォルトの構成のものがビルドされます。ビルドの構成を指定して実行するオプションは若干面倒です。たとえば Release 指定してビルドする場合は以下のように呼び出します。
$ MSBuild /p:Configuration=Release
http://www.atmarkit.co.jp/fdotnet/special/msbuild01/msbuild01_01.html
.NET 以前
VC++6.0 など .NET の前の場合には 以下のようにしてビルドできます。
$ MSDEV.dsw /MAKE "target"
http://q.hatena.ne.jp/1213016943
Qt の場合
Qt の場合には qmake というツールを使って、 Qt 用のプロジェクトファイル(*.proj)から、 Un*x 系では make ファイル、 Windows 上では VC 用のプロジェクトファイルを生成することができます。
Windows 上で VC 用プロジェクトファイルを生成するためには *.proj の TEMPLATE の設定で vcapp を指定する必要があります。ただクロスプラットホームで開発している場合、 vcapp とプロジェクトファイルに記述すると今度は Un*x 系でエラーとなるので以下のようにして qmake を実行する必要があります。
$ qmake -tp vc
Windows 上でこの -tp vc をつけずに qmake を実行するとどうなるかというと、nmake という VC 用のメイクファイルが生成されます。 MSBuild を使うよりも nmake の方がビルドが若干速いようなので、私は Qt を Windows 上でコンパイルする場合 nmake を使っています。
ただし、この nmake は VS のスタートメニューの [Visual Studio 20XX コマンドライン] というところから実行すると上手くいくのですが、それ以外から実行しようとすると環境変数が設定されていないため、エラーとなります。
そこで、 Emacs などからビルドしたい場合には以下の環境変数を設定しておく必要があります。
- PATH
- INCLUDE
- LIB
- LIBPATH
設定する環境変数の値は以下のファイルなどを参考にして設定してください。
(VSのインストールフォルダー)\Common7\Tools\vsvar32.bat
C++ 国際化
細かいところは結構はしょって書いたのですが、いろいろ書いてしまって結構長いです。
国際化というのは主に言語(地域)ごとにメッセージを切り替えることを言います。 他にも通貨記号($)や時間の表し方も言語ごとに違いますし、少数点などはヨーロッパでは, . の使い方が逆だったりしてそれにあわせることなども含みますが、 今回はメッセージの切り替え中心です。
Un*x
C ではこの国際化は標準ライブラリにローケルという名前で古くからあります。
これはメッセージファイルに番号ごとのメッセージを書いておいて、 コード中では最初に言語を設定し、この番号を指定すると設定した言語のメッセージが取得できる という仕組みです。 普通はコード中に番号を直接書くことはしないでしょうから、 番号に対して define や列挙型をヘッダに記述しておいてそれを使うことになります。
この標準ライブラリはそのまま使おうとするとすごくめんどくさいです。 そのため、せっかくあるのになかなか使われず、国際化が進みませんでした。 そこでで出てきたのが GetText です。
これはベースは標準ライブラリを使用しますが、使いやすくなります。
プログラムを作る側は今まで英語メッセージを文字リテラルとして書いていたところを次のように _で囲むだけで済みます。
printf(_("Helow World.!!\n"));このように書いたソースに対してツールを通すとメッセージファイルを作ってくれます。
訳す人はツールでメッセージが抜き出されたものができるので、それに対応する訳を書いて、 また、ツールを通すとその言語用のメッセージファイルが出来ます。
これで国際化が進んで、普通に日本語でアプリケーションが使えるようにとても良かったのですが、 個人的にはこの GetText はあまり好きではありません。
というのも、メッセージやアイコンなどはリソースというのですが、 このリソースはソースと分けて一括で管理したいためです。
翻訳用のメッセージはまとまっているのですが、デフォルトの言語(大抵は英語) はソースコードのあちこちに散らばることになりますし、修正する度にビルドのしなおしが必要となります。
今は国際化するのが当たり前になってきたので、もう GetText はいいんじゃないかと思うのですが、 Linux ではこれが主流です。
統合デスクトップ環境である gnome で使われえている GTK+ は GetText を使っていますし、 KDE の Qt は GetText ではなく独自の国際化を持っているのですが、これも GetText 方式です。
Linux ではない商用 Un*x の世界はというと、こちらの GUI は Motif というライブラリが古くから使われていて、これで CDE (gnome や KDE のもとになっているもの) も作られています。 Motif はさらに古い GUI ツールキットである Xt ライブラリの上に出来ているのですが、 こちらはきちんとリソースが分けられています。
Xt ではテキストファイルであるリソースファイルに以下のような行を書きます。
FooApp.FooDialog.OkButton.label : 了解キーになる方は親子関係で書くことができ、これを Widget の部品の名前とあわせておきます。 そうすると、アプリケーションは起動時にリソースファイルをロードして言語にあわせたラベルになります。
ただ、これは GUI 専用のところがあって、 エラーメッセージのようなコード中で決める文字列は C の国際化を使用する必要があります。
他に有名な国際化ライブラリで ICU というものがあります。
これはリソースの国際化だけではなく、文字コード変換などの機能も含んだ大掛かりなもので、 クロスプラットホームで動作します。 しかし、文字コード変換などは Boost からも使われるようになって、広く使われているのですが、 リソース管理という面ではそれほど使われていない気がします。
これもリソースを分離するタイプでよく考えられていると思うのですが、 やはり、 GUI ツールキットとセットではないと広まりにくいのかも知れません。
Windows
Windows の場合、 .NET 以前は基本的に C の標準ライブラリのようなもので、 番号(ID)に対して文字列を指定し、 ID を指定して文字列を取得します。
ただ、 Visual Studio のような IDE で作るのが普通なので、 メッセージファイルの作成と番号の define 定義が同時にできるような感じになっていて、 そんなに使いづらくもないかなと思います。
.NET では番号を define したものではなく、 'Foo.Bar.Ok' のような文字列で取得できるようになっています。
Windows ではリソースは exe や dll などのバイナリファイルに埋め込んでしまいます。 なので、翻訳がない場合に問題が出てきます。
Un*x 系では言語の指定は環境変数 LANG で行いますが、 Windows では WIN32API などの OS が提供するライブラリでユーザーが設定している言語を取得してきます。
商用アプリなど売るところが決まっている場合は問題ないのですが、 フリーウェアなどの場合はリソース用の dll などで追加して、 言語の設定を自動で行うのではなく、アプリの設定でユーザーがどの言語を選択するかを指定するといった工夫が必要になります。
Un*x 系はというと翻訳ファイルやリソースは分かれているのが普通なので、 翻訳ファイルの置き場所に翻訳ファイルおいてなければデフォルト言語(英語)で表示して、 翻訳を追加したければ、そこにファイルを置くという方式が多いと思います。
ちなみに Qt はクロスプラットホームなので、アイコンなどのリソースを Un*x でも、がんばって取り込む仕組みを持っています。 ただ、翻訳ファイルは別ファイルになっていて、 Un*x のような追加方式にすることもできなくはありません。
できなくはないというのは、見つからなかったら英語にする仕組みはないので、 その辺はアプリ側で実装する必要があったりします。
といった感じが C++ での基本的な国際化の方法じゃないかと思います。
どれも一長一短といった感じで、これだっと言うものはないです。 強いて言えば、 .NET が良いと思うのですが、クロスプラットホームではないです。
(Linux でも動くんじゃないかって話はありますが)
それでクロスプラットホームの大規模のアプリの中には自前で国際化の仕組みをもったものもあります。
例えば、 firefox, thunderbird の Mozilla では テキストファイルである プロパティファイルや DTD を使った Java っぽい国際化ができるようになっています。