重物的initializer_list

时间:2017-07-14 11:22:10

标签: c++ initializer-list

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

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

但我很确定这不是我想要的。我想要的是一个可以接收任意数量的std:vector<T> s避免副本的函数(实际上,它们应该作为const接收,因为我没有在里面修改它们)。理想情况下,我希望能够传递rvalues和lvalues,例如:

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

我对当前声明的问题是我(虽然我没有发现任何明确确认或反驳此消息来源),正如现在一样,初始化列表将复制创建时的向量(我知道在任何情况下复制初始化列表本身时都不会复制它们);它是否正确?如果是这样的话,那就是:

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

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

1 个答案:

答案 0 :(得分:3)

您不需要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是一个糟糕的选择,不仅因为构造上的复制问题,还因为它引用了具有局部范围的元素数组。这里的含义是,如果你想要复制返回它,你最终会得到静默的未定义行为(如果你不小心禁用了RVO,或者编译器没有实现RVO或为initializer_list不正确地实现它,你又失去了运气)

重新编辑:

  

我实际上并没有使用初始化列表初始化任何东西,我只是将它用作轻量级参数容器,并迭代其值并读取向量中的值(我将更新问题以使其更清晰)。这会导致副本的创建吗?

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

是没有害处的。