2

sizeof...() 演算子の clang++ コンパイラからの奇妙な動作のように見えるものに遭遇しました。

template <typename... Args>
void test(tuple<Args...> t) {
    cout << "size: " << sizeof...(Args) << endl;
}

...
test(make_tuple(1, 2)); // prints 'size: 10'

より標準的な方法は次のようになると思います。

template <typename... Args>
void test(tuple<Args...> t) {
   cout << "size: " << tuple_size<tuple<Args...> >::value << endl;
}

test(make_tuple(1, 2)); // prints 'size: 2'

しかし、最初のバージョンで奇妙な値が得られる理由については、まだ興味があります。この場合、 sizeof...() の値は未定義ですか、それともコンパイラの動作がおかしいのでしょうか?

4

1 に答える 1

10

これは、古い可変個引数テンプレートのエミュレーションと真の可変個引数テンプレートの不一致によく似ています。

可変個引数テンプレートが登場する前は、人々は有限数のデフォルトのテンプレートパラメータでそれらをエミュレートすることができました。

struct void_ {}; // marker type not used anywhere else

template <typename T0 = void_,
          typename T1 = void_,
          typename T2 = void_,
          typename T3 = void_,
          typename T4 = void_,
          typename T5 = void_,
          typename T6 = void_,
          typename T7 = void_,
          typename T8 = void_,
          typename T9 = void_>
struct tuple { /* blah blah magic here */ };

これにより、最大10個のパラメータなどtuple<int>を書き込むことができます。tuple<int, double>

tuple_size次に、最初のの前にテンプレートパラメータの数を数えることで実装できますvoid_。残りの機能セットも同様に実装されています。

悲しいことに、このトリックは真の可変個引数テンプレートとの相互作用が非常に不十分です。を指定するtuple<int, double>と、型のtuple<Args...>推定はArgsパックを{int、double、void_、void_、void_、void_、void_、void_、void_、void_}と推定します。これがsizeof...(Args)10を返す理由です。そのパックには確かに10のタイプがありますが、そのうちの8つが単なるマーカーであり、「ここに表示するタイプがない、一緒に移動する」という意味を割り当てることにしました。

コンパイラは私たちの規則を知らないので、すべてを数えます。tuple_sizeこの規則を知っており、気になる実際のタイプのみをカウントします。

于 2012-08-09T02:47:26.370 に答える