initializer_list 对于重物

initializer_list for heavy objects

我有一个这样的(模板化)函数:

template<typename T>
void func(std::initializer_list<std::vector<T>> args)
{
    for (const auto &values : inputValues)
    {
        someOperation(values);
    }
}

但我很确定这不是我想要的。我想要的是一个可以接收任意数量的 std:vector<T> 避免复制的函数(事实上,它们应该作为 const 接收,因为我没有在内部修改它们)。理想情况下,我希望能够同时传递右值和左值,例如:

std::vector<int> myVec {1, 2, 3};
func({myVec, {4, 5}});

我对当前声明的问题是,我 认为(虽然我没有找到任何明确证实或反驳这一点的来源),就像现在一样,初始化列表将在创建时复制向量(我知道在任何情况下复制初始化列表本身时它们都不会被复制);这个对吗?如果是这样的话,就是:

template<typename T>
void func(std::initializer_list<const & std::vector<T>> args)
{
    // ...
}

我在寻找什么?那会允许我使用右值吗?我对不同于初始化列表的选项持开放态度(我不确定我是否能够使用可变参数模板,因为这个函数模板被显式实例化并编译到一个库中,但如果有替代方案,那将会很有趣看看)。

您不需要 initializer_list,因为如果您尝试用它初始化其他 vector,它会强制复制。相反,您希望使用可变模板转发引用:

template<class... T>
bool func(T&&... vectors);

然后你可以 std::forward<T>(vectors)... 你认为合适的。

这可以让您有机会避免复制。

例如

std::vector<int> a;
std::vector<int> b;
std::vector<int> c;
// initialize a, b, and c

func(std::move(a), std::move(b), std::move(c));

如果你想强制所有向量都由 const ref 接收,试试这个:

template<class... Vec>
bool func(const Vec&... vectors);

//...
func(a, b, c); // pass all by const ref

initializer_list 在很多情况下都是一个糟糕的选择,不仅因为构造时复制问题,还因为它引用了具有局部作用域的元素数组。这里的含义是,如果你想复制 return 它,你最终会得到无声的未定义行为(如果你不小心禁用了 RVO,或者编译器没有实现 RVO 或为 initializer_list,你又倒霉了)


重新编辑:

I am not actually using the initializer list to initialize anything, I just use it as a lightweight arguments container and, iterating its values and read the values in the vectors (I'll update the question to make that clearer). Would this also cause the creation of copies?

不,不需要创建任何副本。以这种方式使用 initializer_list 本身没有问题,但这不是它的预期用途。它的预期用途是让 class 构造函数具有 initializer_list 构造函数。如果您正在寻找可以迭代的容器,那么创建一个对其他向量的引用向量也没有什么坏处 (std::vector<const std::vector<int>&>)