📜  C++ 中的列表和转发列表的集合以及示例(1)

📅  最后修改于: 2023-12-03 14:59:48.399000             🧑  作者: Mango

C++ 中的列表和转发列表的集合以及示例

在 C++ 中,列表和转发列表可以用于函数调用、初始化和赋值等。它们提供了一种更加便捷简洁的写法,同时也可以避免由于参数类型不匹配等原因导致的编译错误。

列表初始化和转发列表初始化

列表初始化和转发列表初始化都是 C++11 引入的特性,具体可以参考 cppreference

列表初始化

列表初始化使用花括号 {} 将参数包含起来,例如:

int arr[] = {1, 2, 3};  // 初始化数组
std::vector<int> v = {1, 2, 3};  // 初始化 vector
std::map<std::string, int> m = {{"a", 1}, {"b", 2}};  // 初始化 map

需要注意的是,如果列表初始化的参数类型与指定类型不匹配,编译器将会报错,例如:

int n = {};  // error: narrowing conversion of '{}' from 'std::initializer_list<int>' to 'int' inside { } [-Wnarrowing]
转发列表初始化

转发列表初始化使用圆括号 () 将参数包含起来,例如:

template<typename T>
void foo(T t) {}

foo(1);  // 普通函数调用
foo(std::vector<int>{1, 2, 3});  // 转发列表初始化

需要注意的是,转发列表初始化只能传递参数,不能进行运算,例如:

foo(std::vector<int>(1, 2, 3));  // error: no matching function for call to 'std::vector<int>(int, int, int)'
转发列表

转发列表可以用来在函数调用时转发可变数量的参数,它可以用于任何接受可变数量参数的函数,例如:

template<typename... Args>
void foo(Args&&... args) {}

foo(1, 2, 3);  // 使用转发列表转发参数

在上面的例子中,Args 是一个参数包,可以接受任意数量的参数。Args&&... args 中的 && 表示接受左右值引用,... 表示展开参数包。可以通过 sizeof...(Args) 获取参数包中参数的数量。

转发列表和完美转发

转发列表除了可以用于转发参数以外,还可以用于实现完美转发,即保证传递参数的引用类型和值类型一致,例如:

template<typename T>
void foo(T&& t) {}

int n = 1;
foo(n);  // 将 n 的值转发给 foo
foo(std::move(n));  // 将 n 的右值引用转发给 foo

在上面的例子中,T&& t 表示将参数类型推导为右值引用或左值引用,可以同时接受值类型和引用类型的参数(即完美转发)。

示例代码
#include <iostream>
#include <vector>
#include <map>

template<typename... Args>
void foo(Args&&... args) {
    std::cout << sizeof...(Args) << std::endl;
}

template<typename T>
void bar(T&& t) {}

int main() {
    int arr[] = {1, 2, 3};  // 初始化数组
    std::vector<int> v = {1, 2, 3};  // 初始化 vector
    std::map<std::string, int> m = {{"a", 1}, {"b", 2}};  // 初始化 map

    foo(1, 2, 3);  // 使用转发列表转发参数
    foo(arr[0], arr[1], arr[2]);  // 使用转发列表转发参数
    foo(v.begin(), v.end());  // 使用转发列表转发参数
    foo(m.begin(), m.end());  // 使用转发列表转发参数

    int n = 1;
    bar(n);  // 将 n 的值转发给 bar
    bar(std::move(n));  // 将 n 的右值引用转发给 bar
    return 0;
}