在 C++ 中将子向量作为函数参数传递
Passing sub-vector as function argument in c++
给定一个大小为 10 的向量 v1,我想将 v1 的第一个、第三个和第七个元素作为单个函数参数传递。不是创建另一个向量 v2,按值从 v1 复制三个元素并传递 v2 的引用,有没有更有效的方法来传递参数(即不创建 v2 和按值复制元素)?
您可以将索引与向量一起传递:
std::vector<unsigned> indices = { 1, 3, 5 };
void f(const std::vector<int>& X, const std::vector<unsigned>& idx)
{
// Do something
}
根据所需的行为,您可以传递 vector<reference_wrapper>
或 reference_wrapper
的其他容器:
#include <vector>
#include <functional>
void f(std::vector<std::reference_wrapper<double>>) {}
void g() {
std::vector<double> v(10);
f({v[0], v[2], v[6]});
}
你说你不想创建一个新向量并将所需的元素复制到它 - 一个带有指向 3 个元素的指针的新向量怎么样?还是带有指向元素的指针的元组?
std::vector<Element> items { e0, e1, e2, e3, e4, e5, e6, e7 };
auto tuple = std::make_tuple(&items[0], &items[2], &items[6]);
或者只是一个具有 3 个字段的自定义参数结构 - 指向 3 个向量元素的指针?
或者带有指向 3 个向量元素的指针的原始数组? (也许有一个额外的数组大小函数参数)
std::vector<Element> items { e0, e1, e2, e3, e4, e5, e6, e7 };
Element subItems[3] { &items[0], &items[2], &items[6] };
很多可能性,但我会选择一个带有副本的新向量,除非它不必要地昂贵,在这种情况下,指向原始向量的指针将是第二选择。创建向量不太可能是性能问题。
您可以插入一个转发函数来为您挑选索引:
template <size_t... Is, typename F, typename C>
auto fwd_indices(F func, C& cont)
-> decltype(func(cont[Is]...))
{
return func(cont[Is]...);
}
这是一个零拷贝、零额外对象的解决方案。您可以这样使用该功能:
std::vector<int> v = { .. };
fwd_indices<0, 2, 6>(some_func, v); // calls some_func(v[0], v[2], v[6]);
// which hopefully takes them by-ref
如果您只知道在 运行 时需要转发哪些索引,这是不行的。但是如果你在编译时知道它们,这对我来说似乎很干净。
您可以传递一个迭代器向量:
#include <vector>
#include <iostream>
using itr_type = std::vector<double>::const_iterator;
void doSomethingWithItrVec(std::vector<itr_type> itr_vec) {
for (auto itr : itr_vec)
std::cout << *itr << "\n";
}
int main() {
std::vector<double> v = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
auto begin = v.cbegin();
doSomethingWithItrVec({begin, begin + 2, begin + 6});
}
给定一个大小为 10 的向量 v1,我想将 v1 的第一个、第三个和第七个元素作为单个函数参数传递。不是创建另一个向量 v2,按值从 v1 复制三个元素并传递 v2 的引用,有没有更有效的方法来传递参数(即不创建 v2 和按值复制元素)?
您可以将索引与向量一起传递:
std::vector<unsigned> indices = { 1, 3, 5 };
void f(const std::vector<int>& X, const std::vector<unsigned>& idx)
{
// Do something
}
根据所需的行为,您可以传递 vector<reference_wrapper>
或 reference_wrapper
的其他容器:
#include <vector>
#include <functional>
void f(std::vector<std::reference_wrapper<double>>) {}
void g() {
std::vector<double> v(10);
f({v[0], v[2], v[6]});
}
你说你不想创建一个新向量并将所需的元素复制到它 - 一个带有指向 3 个元素的指针的新向量怎么样?还是带有指向元素的指针的元组?
std::vector<Element> items { e0, e1, e2, e3, e4, e5, e6, e7 };
auto tuple = std::make_tuple(&items[0], &items[2], &items[6]);
或者只是一个具有 3 个字段的自定义参数结构 - 指向 3 个向量元素的指针?
或者带有指向 3 个向量元素的指针的原始数组? (也许有一个额外的数组大小函数参数)
std::vector<Element> items { e0, e1, e2, e3, e4, e5, e6, e7 };
Element subItems[3] { &items[0], &items[2], &items[6] };
很多可能性,但我会选择一个带有副本的新向量,除非它不必要地昂贵,在这种情况下,指向原始向量的指针将是第二选择。创建向量不太可能是性能问题。
您可以插入一个转发函数来为您挑选索引:
template <size_t... Is, typename F, typename C>
auto fwd_indices(F func, C& cont)
-> decltype(func(cont[Is]...))
{
return func(cont[Is]...);
}
这是一个零拷贝、零额外对象的解决方案。您可以这样使用该功能:
std::vector<int> v = { .. };
fwd_indices<0, 2, 6>(some_func, v); // calls some_func(v[0], v[2], v[6]);
// which hopefully takes them by-ref
如果您只知道在 运行 时需要转发哪些索引,这是不行的。但是如果你在编译时知道它们,这对我来说似乎很干净。
您可以传递一个迭代器向量:
#include <vector>
#include <iostream>
using itr_type = std::vector<double>::const_iterator;
void doSomethingWithItrVec(std::vector<itr_type> itr_vec) {
for (auto itr : itr_vec)
std::cout << *itr << "\n";
}
int main() {
std::vector<double> v = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
auto begin = v.cbegin();
doSomethingWithItrVec({begin, begin + 2, begin + 6});
}