1. ホーム
  2. c++

[解決済み] パラメータパックの二重省略演算子「... ...」とは何ですか?

2022-05-18 03:02:08

質問

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

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

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

さて、このトークンの意味は何でしょうか?

edit: 質問タイトルの "......" を SO が "......" に切り捨てたようです、本当は "......" の意味でした。)

どのように解決するのですか?

その変な例はすべて、通常のシングルエリプスの場合と対になっています。

  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言語スタイルのvarargsリストに続くバリアドテンプレート展開です。

以下はテストです。 をテストしてみました。

編集してください。 これは適合しているように見えます。§8.3.5/3では、パラメータリストを形成する一つの方法として

パラメータ宣言リスト opt ... <サブ opt

つまり、ダブルエリプシスとは、パラメータパックで終わるparameter-declaration-listと、それに続くもう一つのエリプシスによって形成されるものです。

カンマは純粋にオプションです。8.3.5/4では、次のように書かれています。

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

これは の中で、抽象宣言子(abstract-declarator)です。 [編集] です。 が、Johannesは、彼らがパラメータ宣言の中の抽象的な宣言子を参照していることをうまく指摘しています。なぜquot;part of a parameter-declarationと言わなかったのか、なぜこの文章は単なる情報提供のメモではないのか...と思っています。

さらに va_begin()<cstdarg> はバラグリストの前にパラメータが必要なので、プロトタイプの 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 );
}