Page's Personal Website

C++ 变长参数解包

2021-01-09
c++

[TOC]

最近,看C++11相关的东西,看到模板变长参数的时候,关于变长参数的代码都看不懂了~

变长参数模板

解包的正确姿势

参考[1][3]中说变长参数模板如何解包的问题,其中一种方法是用逗号表达式+初始化列表的方式,参考[3]

template <class T>
void printarg(T t)
{
   cout << t << endl;
}

template <class ...Args>
void expand(Args... args)
{
   int arr[] = {(printarg(args), 0)...};
}

expand(1,2,3,4);

其中{(printarg(args), 0)…}展开为(printarg(arg1), 0), (printarg(arg2), 0), (printarg(arg3), 0), (printarg(arg4), 0)。 如果,我把调用改成expand(1, 2.987, 3, “abc”);,结果为

1
2.987
3
abc

解包的错误姿势

参考[2]代码

template <typename T>
T func(T value)
{
    return value;
}
template <typename T, typename ... U>
void g(T value, U ...u)
{
    func(u)...; // error C3520: “u”: 必须在此上下文中扩展参数包
}

g(1.2, 3.4, 5.6);

可以看到,用法func(u)…显示的编译错误

error C3520: “u”: 必须在此上下文中扩展参数包

参考[2]中的有网友给出了一些解决办法

int a[] = {0, (func(u), 0)...};

小结

这里我不懂的地方都是属于变长参数范围,总的来说是这个点自己不清楚。所以,看代码就很疑惑。关于我不懂的地方,现在清楚了一点

  • 1.这里的(args)…,就是一个模式后面跟着冒号的表达式,表示对这个模式进行解包
  • 2.解包这个语法使用有限定环境,如果不在限定环境内使用,就会报错必须在此上下文中扩展参数包

变长参数解包

参考[4][5],这篇非常值得拜读!还有些地方虽然没看懂,但是收获颇丰,基本上我的疑惑都是从这里得到解答了。 列两个模板变长参数解包相关的环境 1.Lambda captures

template<class ...Args>
void f(Args... args) {
    auto lm = [&, args...] { return g(args...); };
    lm();
}

2.Brace-enclosed initializers。 解包的正确姿势 中就是属于这种情况 参考[1]中的代码也属于这种情况。开始以为是lambda那种情况,细细分析一下觉得还是属于初始化列表环境。下面是逐行解析:

template<typename T, typename... Ts>
auto printf3(T value, Ts... args) {
    std::cout << value << std::endl;
    (void) std::initializer_list<T>{([&args] {
        std::cout << args << std::endl;
    }(), value)...};
}

(1)保证环境正确:在*std::initializer_list*后面的花括号环境中,可以使用包展开。 (2)包展开语法:模式...,这里的模式是小括号中的部分。一个lambda表达式和value组成的逗号表达式

([&args] {
        std::cout << args << std::endl;
    }(), value)

(3)假设三个参数展开为:([&arg1] {std::cout « arg1 « std::endl;}(), value), ([&arg2] {std::cout « arg2 « std::endl;}(), value), ([&arg3] {std::cout « arg3 « std::endl;}(), value)。 这也就是我最终认为,这个例子里面用到的是初始化列表展开,不是属于lambda环境展开。因为初始化列表展开之后到lambda捕获的时候已经不是一个pack了,而是展开之后逐个的元数了。

参考

[1]modern-cpp-tutorial [2]C++可变参数模板展开 [3]泛化之美–C++11可变模版参数的妙用 [4]Parameter pack [5]形参包


Similar Posts

Comments