同一表达式中多个参数包的多次展开

Multiple expansions of multiple parameter packs in the same expression

本文关键字:表达式 参数      更新时间:2023-10-16

我想问以下代码是否有效。

我想知道在一个表达式中多次扩展参数包的可能性。

#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,};
}

正如您所看到的,代码使用:调试打印机<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仍然没有编译代码。

是的,您的代码是完全有效的。包扩展由一个模式和一个省略号组成,并且可以出现在另一个包扩展的模式中。在标准的第14.5.3/5段中,您会发现:

[…]参数包名称的外观仅通过最内部的封装包扩展进行扩展。包扩展模式应命名一个或多个未通过嵌套包扩展扩展的参数包;[…]

在§14.5.3/4中提到的任何情况下都可以使用包装扩展。举个例子:

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

两个包扩展都有效。第一个的上下文是template-argument-list,而第二个出现在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
}