web-dev-qa-db-ja.com

「... ...」トークンの意味は何ですか?つまり、パラメータパックでの二重楕円演算子

新しいC++ 11ヘッダーのgccの現在の実装を閲覧しているときに、「......」トークンに遭遇しました。次のコード コンパイルがうまくいく [ideone.com経由]であることを確認できます。

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

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

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

編集:SO質問タイトルの "......"を "..."にトリミングしたように見えます。私は本当に "......"を意味していました。:)

110
Vitus

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

_  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は言う

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

これはが抽象宣言子内にある[edit]ですが、ヨハネスはそれらがパラメータ宣言内の抽象宣言子を参照します。なぜ彼らが「パラメータ宣言の一部」と言わなかったのか、そしてなぜその文は単なる情報メモではないのか…。

さらに、_<cstdarg>_のva_begin()にはvarargsリストの前にパラメーターが必要なため、C++で特に許可されているプロトタイプf(...)は役に立たない。 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 );
}
_
78
Potatoswatter

テンプレートバージョンでは、vs2015でコンマを区切ることが不可欠です。

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

インスタンス化の例は次のとおりです。

    X<int(int...)> my_va_func;

よろしく、FM。

3
Red.Wave