11

次のコードが有効かどうかお尋ねしたいです。

1 つの式でパラメーター パックを複数回展開する可能性について疑問に思います。

#include <iostream>
#include <tuple>

class ExpandWithConstructor
{
    public:
        template <typename ... T>
        ExpandWithConstructor( T... args) { }
};

template <typename T>
int PrintArgs( T arg )
{
    std::cout << arg  << ", ";
    return 0;
}

template <typename Head, typename ... T>
class DebugPrinter: public DebugPrinter<T...>
{
    public:
        DebugPrinter() { }

        template< typename ...Y>
        DebugPrinter( Y ... rest ) 
        {   
            std::cout << "Construction of: " << __PRETTY_FUNCTION__ << " Values: " ;
            ExpandWithConstructor{PrintArgs( rest)...};
            std::cout << std::endl;
        }   

};

template <typename Head>
class DebugPrinter< Head >
{   
    public:
};  

template <typename ... T>
class TypeContainer: public std::tuple<T...>
{
    public:
        TypeContainer(T... args):std::tuple<T...>(args...){};
};

template <typename... T1> class CheckVariadic;

template <typename... T1, typename ...T2>
class CheckVariadic< TypeContainer<T1...>, TypeContainer<T2...>> :
          public DebugPrinter< T1, T2, T1...>...
{
    public:
        CheckVariadic( T1... args1, T2... args2, T1... args3): DebugPrinter< T1, T2, T1...>(args1, args2..., args1)... {}
};


int main()
{
    CheckVariadic< TypeContainer<int,float>, TypeContainer<char, void*>> checkVariadic1{ 1,2.2,'c',(void*)0xddddd,5,6.6,};
}

ご覧のとおり、コードは次を使用しています: DebugPrinter< T1, T2, T1...>...

T1 が "int,float" で指定され、T2 が "char,void*" である場合、これは次のように展開されます。

DebugPrinter< T1, T2, int, float>...

に展開します

DebugPrinter< int, char, int, float>
DebugPrinter< float, void*, int, float>

同じ展開は次の場合にも当てはまります。

 DebugPrinter< T1, T2, T1...>(args1, args2..., args1)...

コードはclang3.3でコンパイルされますが、gcc4.8.1ではコンパイルされないため、コードが有効かどうかを尋ねたい.

更新: gcc 7.2 はまだコードをコンパイルしませんでした。

4

1 に答える 1

3

はい、あなたのコードは完全に有効です。パック展開はパターンと省略記号で構成され、別のパック展開のパターンに表示できます。標準の §14.5.3/5 の段落では、次のことがわかります。

[...] パラメータ パックの名前の外観は、最内包パック展開によってのみ展開されます。パック展開のパターンは、ネストされたパック展開によって展開されない 1 つ以上のパラメーター パックを指定する必要があります。[...]

パック拡張は、§14.5.3/4 で言及されているあらゆるコンテキストで使用できます。あなたの例を考えると:

DebugPrinter< T1, T2, T1...>...

どちらのパック拡張も有効です。最初のコンテキストは aですtemplate-argument-listが、2 番目のコンテキストは a に表示されますbase-specifier-list

標準テキストで提供される例:

template<class ... Args>
void g(Args ... args) {                   // OK: Args is expanded by the function
                                          // parameter pack args
    f(const_cast<const Args*>(&args)...); // OK: “Args” and “args” are expanded
    f(5 ...);                             // error: pattern does not contain any
                                          // parameter packs
    f(args);                              // error: parameter pack “args” is not
                                          // expanded
    f(h(args ...) + args ...);            // OK: first “args” expanded within h,
                                          // second “args” expanded within f
}
于 2013-09-07T01:52:41.657 に答える