116

新しい C++11 ヘッダーの gcc の現在の実装を参照しているときに、"......" トークンに出くわしました。次のコードが[godbolt.org 経由で] 正常にコンパイルされることを確認できます。

template <typename T>
struct X
{ /* ... */ };

template <typename T, typename ... U>
struct X<T(U......)> // this line is the important one
{ /* ... */ };

では、このトークンの意味は何ですか?

編集:質問のタイトルの「......」が「...」にトリミングされたように見えますが、本当に「......」を意味していました。:)

4

2 に答える 2

80

その奇妙さのすべてのインスタンスは、通常の単一の省略記号のケースとペアになっています。

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......)>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes...) const>
    { typedef _Res result_type; };

  template<typename _Res, typename... _ArgTypes>
    struct _Weak_result_type_impl<_Res(_ArgTypes......) const>
    { typedef _Res result_type; };

私の推測では、二重省略記号は意味が に似ていると思います_ArgTypes..., ...。つまり、可変引数テンプレート展開の後に C スタイルの可変引数リストが続きます。

これがその理論を裏付けるテストです…これまでで最悪の疑似オペレーターの新しい勝者ができたと思います。

編集:これは準拠しているようです。§8.3.5/3 では、パラメーター リストを次のように形成する 1 つの方法について説明しています。

パラメタ宣言リストopt ... opt

したがって、二重省略記号は、パラメーター パックで終わるパラメーター宣言リストと、それに続く別の省略記号によって形成されます。

コンマは完全にオプションです。§8.3.5/4 は言う

構文的に正しく、「...」が抽象宣言子の一部でない場合、「, ...」は「...」と同義です。

これabstract-declarator内にあります[編集]が、Johannesは、パラメーター宣言内のabstract-declaratorを参照していることを適切に指摘しています. なぜ彼らは「パラメータ宣言の一部」と言わなかったのか、そしてなぜその文は単なる情報メモではないのだろうか…</p>

さらに、va_begin()in<cstdarg>は varargs リストの前にパラメーターを必要とするため、f(...)C++ で特に許可されているプロトタイプは役に立ちません。C99 との相互参照は、プレーン C では違法です。したがって、これは最も奇妙なことです。

使用上の注意

リクエストに応じて、二重省略記号のデモを次に示します。

#include <cstdio>
#include <string>

template< typename T >
T const &printf_helper( T const &x )
    { return x; }

char const *printf_helper( std::string const &x )
    { return x.c_str(); }

template< typename ... Req, typename ... Given >
int wrap_printf( int (*fn)( Req... ... ), Given ... args ) {
    return fn( printf_helper( args ) ... );
}

int main() {
    wrap_printf( &std::printf, "Hello %s\n", std::string( "world!" ) );
    wrap_printf( &std::fprintf, stderr, std::string( "Error %d" ), 5 );
}
于 2011-04-11T18:32:25.780 に答える