最終更新日時(UTC):
が更新

履歴 編集

テンプレートでの連続した右山カッコを許可 [N1757](C++11)

このページはC++11に採用された言語機能の変更を解説しています。

のちのC++規格でさらに変更される場合があるため関連項目を参照してください。

概要

C++03では、2つ以上連続する右山カッコが出現する場合には、間にスペースを入力する必要があった:

vector<basic_string<char> >; // OK
vector<basic_string<char>>;  // コンパイルエラー : >>は右シフト演算子と見なされる

C++11からは、vector<basic_string<char>>のように、2つ以上連続する右山カッコの間に、スペースを入力する必要がなくなった。

仕様

左山カッコがアクティブな場合(対応する右山カッコがまだ現れていない場合)、丸カッコ内を除いて、>>は右シフト演算子ではなく2つの連続する右山カッコとして扱われる。

A<(X>Y)> a; // 最初の>トークンは丸カッコ内に現れるので、
            // 右山カッコとしては扱われない。
            // 左の山カッコがアクティブで、非丸カッコ内に
            // 最も近しい右山カッコがないため、
            // 2つ目の>トークンは右山カッコと見なされる。

A<X>Y> b;   // コンパイルエラー
            // 1つ目の>トークンが右山カッコとして見なされ、
            // 2つ目の>トークンがoperator>()と見なされる。

ただしこの仕様により、C++03までの以下のようなプログラムの動作が変更となる:

#include <iostream>

template<int I> struct X {
  static int const c = 2;
};
template<> struct X<0> {
  using c = int;
};
template<typename T> struct Y {
  static int const c = 3;
};
static int const c = 4;
int main() {
  std::cout << (Y<X<1> >::c >::c>::c) << '\n';
  std::cout << (Y<X< 1>>::c >::c>::c) << '\n';
}

C++03での出力:

0
3

C++11での出力:

0
0

#include <vector>
#include <string>

int main()
{
  using StringVector = std::vector<std::basic_string<char>>; // OK

  std::basic_string<char> str = "hello";
  static_cast<const std::basic_string<char>>(str); // OK
}

この機能が必要になった背景・経緯

C++03までは構文解析の都合で、テンプレートの右山カッコが不等号やシフト記号と曖昧になっていた。そのためにテンプレートの右山カッコを明示する際には、2つの連続する右山カッコの間にスペースを必要とした。

これは小さな問題ではあるが、永続的で迷惑な問題であったために、この問題を除去する価値があると判断され、GNUやEDGといったコンパイラベンダーによるいくつかの実験を経て、標準C++に、連続する右山カッコに関するルールが追加されることとなった。

検討されたほかの選択肢

C++11で採択された方式は、テンプレートの型パラメータと非型パラメータどちらにも対応するものだったが、それ以外の方式も提案された。

ひとつは、テンプレートの型パラメータのみを構文解析で特別扱いし、非型テンプレートパラメータをそのままとするもの。これによって、A<B<int>>適格だが、C<D<12>>不適格となる。

もうひとつは、2つの連続した>トークンの問題を完全に除去するために、シフト演算子の構文もまた> >のように間にスペースを入れるよう許可すること。int i = 10000 > > x;。このアプローチは新たな曖昧さは導入しないが、プリプロセッサの##(トークン連結)において後方互換性の問題を発生させる。

こういった、現在の方式と合わせて3つが検討された。現在の方式によって意味が変わるプログラムは使われている可能性が低かったこともあり、現在の方式が採用された。

参照