2013-12-13

C++03とC++11の違い: テンプレート編

京都C++勉強会の宣伝のために、C++03とC++11の違いを、少しづつ解説することにした。

今回は、テンプレートについて、C++03とC++11/14の違いを取り上げる。

C++11では、export機能が廃止となった。

exportは、実装例が極めて少なかったために、C++11では廃止となった。

この変更による互換性の問題は、ほとんどないだろう。というのも、export機能自体が使われていなかったのだから。

C++11では、入れ子となったテンプレートの連続したアングルブラケットの間に、空白文字を挟む必要がなくなった。

template < typename T >
struct S { } ;

// C++03では違法
// C++11では合法
S<S<int>>> s ;

C++03では、右シフト演算子、operator >>と文法上曖昧になるため、必ず空白文字を挟まなければならなかったのだ。

// 空白文字が必要
S<S<int>> > s ;

このような些細な文法上の問題は、利用者の混乱を防ぐために、コンパイラーの努力で何とかするべきだという意見により、C++11では、このような場合、演算子ではなくテンプレートのアングルブラケットだと解釈するようになった。

この変更により、C++03では、右シフト演算子と解釈されるために合法だったコードの解釈が変わってしまう。

template <class T> struct X { };
template <int N> struct Y { };

// C++03では合法、1 >> 2は右シフト式
// C++11では違法、文法上の誤り。
X< Y< 1 >> 2 > > x;

ただし、このようなコードは稀であろうから、おそらくは大丈夫だろう。

C++11では、内部リンケージを持つ関数を依存呼び出しできるようになった。

C++03では、非修飾名での依存呼び出しの際には、外部リンケージの関数しか考慮されなかった。内部リンケージの関数はオーバーロード解決に置いて考慮されなかった。そのため、以下のようなコードは、厳格に規格準拠のC++03の実装とC++11の実装で実行した場合、挙動が異なる。

void f( long ) { } // #1
static void f( int ) { } // #2


template < typename T >
void g( T x )
{
    // C++03では#1を呼ぶ
    // C++11では#2を呼ぶ
    f( x ) ;
}

int main()
{
    g( 0 ) ;
}

C++03では、外部リンケージの関数しか考慮されないので、#2が呼ばれることはない。C++11では、単に実装の簡単化のため、内部リンケージも考慮されることになったので、#2が呼ばれる。

このこととは直接関係ないが、依存呼び出しにおいては、プログラムの全翻訳単位の、その文脈で発見できない名前も含めたすべての外部リンケージを持つオーバーロード関数の候補で、もし、オーバーロード解決の結果、より最適な候補となる関数が存在した場合は、プログラムは違法となる。

例えば、unit_1.cpp, unit_2.cppという、2つのソースファイル、2つの翻訳単位からなるプログラムがあったとする。

// unit_1.cpp
void f( int ) { } // #1
// unit_2.cpp
void f( long ) { } // #2

template < typename T >
void g( T x )
{
    f( x ) ; // 依存呼び出し
}

int main()
{
    g( 0 ) ; // 違法
}

このコードは違法である。なぜならば、依存呼び出しで#2が最適関数となるが、別の翻訳単位で、名前は見つからないものの、より最適な関数があるために、プログラムは違法となる。

これは、テンプレートの特殊化が翻訳単位ごとに異なる結果となることを防ぐためである。

依存名というのは厄介だ。

江添とボレロ村上の京都C++勉強会が、12月16日に行われる。これを書いている時点では、まだ空きがあるので、最新のC++14の新機能と、コンパイル時レイトレーシングを勉強したければ、ATNDで参加申し込みをせよ。

江添とボレロ村上の京都C++勉強会 | 集客ならイベントアテンド

当日はUstreamによる配信もある

http://ustream.tv/channel/hatenatech

また、私の書いたC++11のコア言語を完全に解説した参考書もある。

Gumroadで購入: C++11参考書:C++11の文法と機能

今すぐ閲覧: C++11: Syntax and Feature

誤りがあればGitHubでPull Requestせよ: https://github.com/EzoeRyou/cpp-book

この参考書は、C++の規格のみを参照して記述しており、特定のC++の実装(コンパイラー)で確かめただけで合法、違法を判断する、世間一般によくある駄本とは根本的に質が異なる本である。本書に誤りがあるとすれば、

  1. 誤字脱字
  2. 筆者の規格文面の解釈間違い
  3. 規格文面の誤り

だけである。まだ、世の中の安定版コンパイラーはC++11の規格をバグフリーで完全に実装していない。

No comments: