2013-5-26[日] c++03コンパイラの機能実装の比較
昔 ow や dmc のc++の(文法)実装状態をチェックしてる表をみたことあったなあ、と探してみれば、すぐみつかる.
http://cmeerw.org/prog/freecpp/
最終更新が2006で、それ以前のコンパイラの比較だけれど、チェックプログラムのソースが公開されていたので、ow 含むそれらよりも新しい(ヴァージョンの)コンパイラで試してみた。
もとより網羅されてるわけでないし今時のc++11世代のコンパイラの比較としては不十分だけど(SFINAEのチェックもなさげ)、owやdmcが以前よりよくなっているかを見る分には、と。
| | dmc 8.56 | ow 1.9 | 4.7.1 tdm | clang3.1 (+mingw462) | vc8 | vc9 | vc11 | bcc 5.5.1 |
1 | digraph | pass | fail[c] | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
2 | alternative tokens | pass | pass | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
3 | new style casts | pass | pass | pass | fail[c] / 実質pass | pass | pass | pass | pass |
4 | bool | pass | pass | pass | pass | pass | pass | pass | pass |
5 | bool condition | pass | pass | pass | pass | pass | pass | pass | pass |
6 | mutable | pass | pass | pass | pass | pass | pass | pass | pass |
7 | explicit | pass | pass | pass | pass | pass | pass | pass | pass |
8 | typename | pass | pass | pass | pass | pass | pass | pass | pass |
9 | covariant return | pass | pass | pass | pass | pass | pass | pass | pass |
10 | arrow operator return | pass | pass | pass | pass | pass | pass | pass | fail[c] |
11 | overload enum | pass | pass | pass | pass | fail[c] | fail[c] | fail[c] | pass |
12 | nested class fwd decl | pass | pass | pass | pass | pass | pass | pass | pass |
13 | friend namespace class | pass | pass | pass | pass | pass | pass | pass | pass |
14 | class name injection | pass | pass | pass | pass | pass | pass | pass | fail[c] |
15 | friend name injection | fail[e] | pass | pass | pass | pass | pass | pass | fail[e] |
16 | static const int | pass | pass | pass | pass | pass | pass | pass | pass |
17 | delete const | pass | pass | pass | pass | pass | pass | pass | pass |
18 | return void | pass | pass | pass | pass | pass | pass | pass | pass |
19 | new scoping | pass | pass | pass | pass | pass | pass | pass | pass |
20 | if stmt cond | pass | pass | pass | pass | pass | pass | pass | pass |
21 | switch stmt cond | pass | pass | pass | pass | pass | pass | pass | pass |
22 | while stmt cond | pass | pass | pass | pass | pass | pass | pass | fail[c] |
23 | for stmt cond | pass | pass | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
24 | defarg scope | fail[c] | fail[c] | pass | pass | pass | pass | pass | fail[c] |
25 | namespace enum | pass | pass | pass | pass | pass | pass | pass | pass |
26 | namespace template | pass | pass | pass | pass | pass | pass | pass | pass |
27 | namespace template func | pass | pass | pass | pass | pass | pass | pass | pass |
28 | using namespace template | pass | pass | pass | pass | pass | pass | pass | pass |
29 | template non type | pass | pass | pass | pass | pass | pass | pass | pass |
30 | explicit template instantiation | pass | pass | pass | pass | pass | pass | pass | pass |
31 | template default all | pass | pass | pass | pass | pass | pass | pass | pass |
32 | template default dependent arg | pass | pass | pass | pass | pass | pass | pass | pass |
33 | template template arg | pass | fail[c] | pass | pass | pass | pass | pass | pass |
34 | template function explicit | pass | pass | pass | pass | pass | pass | pass | pass |
35 | new template specialization | pass | pass | pass | pass | pass | pass | pass | pass |
36 | partial template specialization | pass | pass | pass | pass | pass | pass | pass | pass |
37 | partial ordering class templates | pass | pass | pass | pass | pass | pass | pass | pass |
38 | member template class | pass | fail[c] | pass | pass | pass | pass | pass | pass |
39 | member template function | pass | fail[c] | pass | pass | pass | pass | pass | pass |
40 | bad alloc | fail[e] | pass | pass | pass | pass | pass | pass | pass |
41 | bad typeid | fail[e] | pass | pass | pass | pass | pass | pass | pass |
42 | throwing destructor | pass | pass | pass | pass (c++11fail[e]) | pass | pass | pass | pass |
43 | koenig lookup | pass | fail[c] | pass | pass | pass | pass | pass | pass |
44 | two phase lookup | pass | pass | pass | pass | fail[e] | fail[e] | fail[e] | fail[e] |
45 | empty base opt | pass | pass | pass | pass | pass | pass | pass | fail[e] |
46 | return value opt | pass | pass | pass | pass | pass | pass | pass | fail[e] |
47 | static assertions | pass | fail[c] | pass | pass | fail[c] | fail[c] | pass | fail[c] |
48 | right angle brackets | fail[e] | pass | pass | pass | pass | pass | pass | fail[e] |
49 | func predefined | pass | pass | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
50 | hex float literal | pass | fail[c] | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
51 | long long | pass | pass | pass | pass | pass | pass | pass | fail[c] |
52 | restrict | fail[c] | fail[c] | fail[c] | fail[c] | fail[c] | fail[c] | fail[c] | fail[c] |
53 | variable array | pass | fail[c] | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
54 | dynamic sizeof | pass | fail[c] | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
55 | empty macro argument | pass | pass | pass | pass | pass | pass | pass | pass |
56 | enum trailing comma | pass | pass | pass | pass | pass | pass | pass | pass |
57 | flexible array member | pass | pass | pass | pass | pass | pass | pass | pass |
58 | compound literal | fail[c] | fail[c] | pass | pass | fail[c] | fail[c] | fail[c] | fail[c] |
補足
- いずれもwin用32bit版コンパイラ. win8でコンパイル&実行.
- fallにつけてる[c]はコンパイル出来なかった場合、[e]は実行結果で0以外を返した場合、を表してる.
- 4.7.1tdm は mingw 4.7.1 tdm版.
- clang v3.1 はllvm公式のmingw用バイナリを、本家 mingw g++4.6.2 の環境に上書きしたもの。
- 元表にあるow1.6やdmc8.4.5は試していない(インストールしてない)ので元表をみてください.
- vc8は元表にもあるけれど return void の結果が違ってる.
- 47,48のみ必要ならば c++11 をコンパイルするオプションをつけている.(他はつけていない. 実はclangの不具合回避)
結果に fail があるチェックについて
- 1 digraph: 交代記号( '{' が'<:'等) が使えるか.
- 2 alternative tokens: and や and_eq のような記号の交代予約語が使えるか. ※ iso646.h(ciso646) で同様のものが#define定義されてる
- 3 new style casts: const_cast<T>(t)のようなc++からのキャストが使えるか。clang が fail になっているのは本題とは別の virtual void A::f(); の実体が定義されていないことによるものでソースを実体定義に修正すれば問題なくパス。(このエラーは clangの挙動でも問題無いと思うけど、他のコンパイラがコンパイルできていることが興味深いかも)
- 10 arrow operator return: メンバーのoperator->()の返型がT*,T,T&でない場合にコンパイルできるか.
- 11 overload enum: enum型を基本整数型とは別型として関数オーバーロードできるか?
- 14 class name injection: クラス名インジェクションが機能してるか ※このソースだと B() : ns::A() {} でなく B::B() : A() {} になっているところ.
- 15 friend name injection: friend名インジェクションが機能してるか ※class内friend 定義したものはクラス外(非friend)で定義されたものよりも名前検索の順位が低く、またそのことは引数のマッチよりも優先される...ってことかな。
- 22 while stmt cond: while の条件式でローカル変数を定義できるか
- 23 for stmt cond: for の条件式(2文目)でローカル変数を定義できるか
- 24 defarg scope: デフォルト引数スコープの扱いに関するテスト. ow はメンバー関数のデフォルト引数は関数宣言側ならOKだが定義側だとNGのようで、また、関数内での外部関数宣言ではデフォルト引数が使えない模様。bcc5.5.1 はデフォルト引数の問題でなく static const 変数の扱いが定数でないためのfailで、static const int c=3;の代わりに struct B に先立ち enum {c=3}; を定義すれば ok.
- 34 template template arg: template<template<class T> class T1> のような template template 引数を使えるか
- 38 member template class: クラス・メンバーとしてclass テンプレートが使えるか. ※ow1.9 はクラス定義内では使えるが、クラス定義外でtemplateを2回使う記述はNG.
- 39 member template function: クラス・メンバーとして関数 テンプレートが使えるか. ※ow1.9 はクラス定義内では使えるが、クラス定義外でtemplateを2回使う記述はNG.
- 40 bad alloc: new が メモリー不足の時に bad alloc を投げるか. ※ dm 標準では行えてないが stlport のようにライブラリ実装で対処可能.
- 41 bad typeid: Typeidの引数が不正だった場合 bad_typeid を投げるか.
- 42 throwing destructor: デストラクタ中に例外を投げることができるか. ※ clang++ 3.1 では通常は問題ないが -std=c++11 をつけでコンパイルすると実行時にハングした.
- 43 koenig lookup: koenig lookup(ADL) が機能してるか. (関数呼出で、その引数の型が定義されている namespace から関数名をみつけられるか)
- 44 two phase lookup:スコープ違いで同名のある関数の呼出が正しく行われるか
- 45 empty base opt: 継承元class(struct)にメンバー変数が無い時0バイトにオプティマイズするか
- 46 return value opt: クラス変数を返す時、コピーを発生させないようオプティマイズするか (VCはオプティマイズ指定しないとコピーになる)
- 47 static assertions:[c++11]: static_assert があるか
- 48 right angle brackets:[c++11]: templateで閉じカッコ2つを 空白を入れずくっつけて >> と記述して大丈夫か
- 49 func predefined:[c99, c++11]: 関数名文字列 __func__ が使えるか
- 50 hex float literal:[c99, c++11]: 16進数浮動小数点表記が使えるか
- 51 long long:[c99, c++11]: long long を使えるか ※ bcc5.5.1は __int64 ならある
- 52 restrict:[c99]: restrict 指定が使えるか. ※ c++11には入らなかった機能.
- 53 variable array:[c99]: 動的ローカル配列が使えるか. ※ c++14に入るかもらしい(?)
- 54 dynamic sizeof:[c99]: 動的ローカル配列に対するsizeofが機能するか ※ c++14には入らない.(c++のsizeofはあくまでコンパイル時に決定できるモノのみ)
- 55 empty macro argument:[c99]: 空のマクロ引数を許容するか ※ bcc はこのソースでは大丈夫だが、引数が1つの場合 NG
- 58 compound literal:[c99, c++11]: (struct A){1, 2} のような構造体リテラル表記できるか.
bcc 5.5.1 を表に加えるんじゃなかった...面倒増えてしまった(いや本当はpassしてるのもひと通りみたほうがよいくらいだけど)
vc が overload enum、two phase lookup あたりを修正しないのは、互換性がらみなんでせうかね? (既存の巨大ソースだと意図せず依存してそうな場合もありえそうだし).