如何编写可以接受数组或向量的函数?
How to write a function that can take in an array or a vector?
我想编写一个带有一个参数的 C++ 函数,以便可以传入以下任何一种类型:
std::vector<int>
std::array<int>
int array[numElements]
int *ptr = new int[numElements]
etc
模板化是完成此任务的最佳方式吗?
如果你希望只能做 func(v)
你做不到,因为我无法想到你的函数可以推断出动态分配的大小 int[numElements]
.
包装它的一个好方法是采用一对前向迭代器,也就是说,如果您只需要一个接一个地迭代项目,因为随机访问在某些容器上非常糟糕,例如 std::list
.
template<class FWIt>
void func(FWIt a, const FWIt b)
{
while (a != b)
{
std::cout << "Value: " << *a << '\n';
++a;
}
}
template<class T>
void func(const T& container)
{
using std::begin;
using std::end;
func(begin(container), end(container));
}
这适用于以下情况:
int array[5] = {1, 2, 3, 4, 5};
func(array);
int* dynarray = new int[5]{1, 2, 3, 4, 5};
func(dynarray, dynarray + 5);
std::vector<int> vec{1, 2, 3, 4, 5};
func(vec);
func(vec.begin(), vec.end());
std::list<int> list{1, 2, 3, 4, 5};
func(list);
编辑: 由于@DanielH 的更改,这也可以通过直接传递原始数组而不是作为两个指针来工作(但仍然不适用于动态分配的数组)。
您无法将所有列出的类型添加到一个函数模板中。但是,您可以重载函数模板,这将解决 std::vector<>
的问题,
std::array<>
和 Type array[numElements]
.
template<typename Iter>
void funArray(const Iter begin, const Iter end)
{
std::cout << "Actual code here\n";
}
template<typename Container> void funArray(const Container& arr)
{
funArray(std::begin(arr), std::end(arr)); //std::vector or std::array
}
现在你可以写:
int main()
{
const std::size_t numElements = 5;
std::vector<int> vec;
std::array<int, numElements> arr;
int array[numElements];
int *ptr = new int[numElements];
funArray(vec);
funArray(arr);
funArray(array);
funArray(ptr, ptr+numElements);
return 0;
}
但是,对于动态分配的数组,你需要按照用户@Asu的建议使用。
编辑:删除了多余的重载。
template<typename T, std::size_t N> void funArray(const T (&arr)[N]) {}
正如@Daniel H指出的那样,上面的C类型数组函数模板重载是徒劳的,因为它可以由第二个重载处理(template<typename Container>
), 通过直接推导到 C 类型数组。
Would templating be the best way to accomplish this?
视情况而定。如果您正在编写一个进入 header 的函数,因此可以在以后用于进一步编译,那么 - 是的,可能:
template <typename IntContainer>
void f(Container& c);
或
template <typename IntContainer>
void f(const Container& c);
但是,如果只编译一次实现,您应该考虑:
void f(gsl::span<int> sp);
或
void f(gsl::span<const int> sp);
使用跨度。如果您还没有听说过它们,请阅读:
What is a "span" and when should I use one?
此函数将能够获取几乎所有变量 as-is:std::vector
、std::array
和普通(大小)数组无需额外语法即可传递.但是,对于指针,您需要调用类似 f(gsl::make_span{ptr, numElements})
.
的方法
PS - 第三种选择,在标准库中很常见,是将交互器而不是容器作为参数。这也需要模板,所以它类似于第一个选项。
span
似乎是您要查找的内容。等待 C++20 :-) 或使用 GSL 中的 span。请参阅 什么是“跨度”,我应该在什么时候使用它?
。示例如下。
#include <array>
#include <iostream>
#include <vector>
#if __cplusplus > 201709L
#include <span>
using std::span;
#else
#include <gsl/gsl>
using gsl::span;
#endif
void func(span<int> data){
for(auto i : data){
std::cout << i << ' ';
}
std::cout <<'\n';
}
int main(){
std::vector<int> stdvec(3);
func(stdvec);
std::array<int,3> stdarr;
func(stdarr);
int carr[3];
func(carr);
int *ptr = new int[3]();
func({ptr,3});
delete []ptr;
return EXIT_SUCCESS;
}
如果他们都使用 int
那么你可以简单地接受开始和结束指针。您可以对它们使用标准的算法,因为指针是迭代器。
void my_func(int const* begin, int const* end)
{
std::for_each(begin, end, [](int i){
std::cout << i << '\n';
});
}
然后:
std::vector<int> v;
std::array<int> a;
int array[numElements];
int* ptr = new int[numElements];
my_func(v.data(), v.data() + v.size());
my_func(a.data(), a.data() + a.size());
my_func(std::begin(array), std::end(array));
my_func(ptr, ptr + numElements);
传递两个 迭代器(通用或其他)的好处是您不必将整个容器传递给算法。
我想编写一个带有一个参数的 C++ 函数,以便可以传入以下任何一种类型:
std::vector<int>
std::array<int>
int array[numElements]
int *ptr = new int[numElements]
etc
模板化是完成此任务的最佳方式吗?
如果你希望只能做 func(v)
你做不到,因为我无法想到你的函数可以推断出动态分配的大小 int[numElements]
.
包装它的一个好方法是采用一对前向迭代器,也就是说,如果您只需要一个接一个地迭代项目,因为随机访问在某些容器上非常糟糕,例如 std::list
.
template<class FWIt>
void func(FWIt a, const FWIt b)
{
while (a != b)
{
std::cout << "Value: " << *a << '\n';
++a;
}
}
template<class T>
void func(const T& container)
{
using std::begin;
using std::end;
func(begin(container), end(container));
}
这适用于以下情况:
int array[5] = {1, 2, 3, 4, 5};
func(array);
int* dynarray = new int[5]{1, 2, 3, 4, 5};
func(dynarray, dynarray + 5);
std::vector<int> vec{1, 2, 3, 4, 5};
func(vec);
func(vec.begin(), vec.end());
std::list<int> list{1, 2, 3, 4, 5};
func(list);
编辑: 由于@DanielH 的更改,这也可以通过直接传递原始数组而不是作为两个指针来工作(但仍然不适用于动态分配的数组)。
您无法将所有列出的类型添加到一个函数模板中。但是,您可以重载函数模板,这将解决 std::vector<>
的问题,
std::array<>
和 Type array[numElements]
.
template<typename Iter>
void funArray(const Iter begin, const Iter end)
{
std::cout << "Actual code here\n";
}
template<typename Container> void funArray(const Container& arr)
{
funArray(std::begin(arr), std::end(arr)); //std::vector or std::array
}
现在你可以写:
int main()
{
const std::size_t numElements = 5;
std::vector<int> vec;
std::array<int, numElements> arr;
int array[numElements];
int *ptr = new int[numElements];
funArray(vec);
funArray(arr);
funArray(array);
funArray(ptr, ptr+numElements);
return 0;
}
但是,对于动态分配的数组,你需要按照用户@Asu的建议使用。
编辑:删除了多余的重载。
template<typename T, std::size_t N> void funArray(const T (&arr)[N]) {}
正如@Daniel H指出的那样,上面的C类型数组函数模板重载是徒劳的,因为它可以由第二个重载处理(template<typename Container>
), 通过直接推导到 C 类型数组。
Would templating be the best way to accomplish this?
视情况而定。如果您正在编写一个进入 header 的函数,因此可以在以后用于进一步编译,那么 - 是的,可能:
template <typename IntContainer>
void f(Container& c);
或
template <typename IntContainer>
void f(const Container& c);
但是,如果只编译一次实现,您应该考虑:
void f(gsl::span<int> sp);
或
void f(gsl::span<const int> sp);
使用跨度。如果您还没有听说过它们,请阅读:
What is a "span" and when should I use one?
此函数将能够获取几乎所有变量 as-is:std::vector
、std::array
和普通(大小)数组无需额外语法即可传递.但是,对于指针,您需要调用类似 f(gsl::make_span{ptr, numElements})
.
PS - 第三种选择,在标准库中很常见,是将交互器而不是容器作为参数。这也需要模板,所以它类似于第一个选项。
span
似乎是您要查找的内容。等待 C++20 :-) 或使用 GSL 中的 span。请参阅 什么是“跨度”,我应该在什么时候使用它?
。示例如下。
#include <array>
#include <iostream>
#include <vector>
#if __cplusplus > 201709L
#include <span>
using std::span;
#else
#include <gsl/gsl>
using gsl::span;
#endif
void func(span<int> data){
for(auto i : data){
std::cout << i << ' ';
}
std::cout <<'\n';
}
int main(){
std::vector<int> stdvec(3);
func(stdvec);
std::array<int,3> stdarr;
func(stdarr);
int carr[3];
func(carr);
int *ptr = new int[3]();
func({ptr,3});
delete []ptr;
return EXIT_SUCCESS;
}
如果他们都使用 int
那么你可以简单地接受开始和结束指针。您可以对它们使用标准的算法,因为指针是迭代器。
void my_func(int const* begin, int const* end)
{
std::for_each(begin, end, [](int i){
std::cout << i << '\n';
});
}
然后:
std::vector<int> v;
std::array<int> a;
int array[numElements];
int* ptr = new int[numElements];
my_func(v.data(), v.data() + v.size());
my_func(a.data(), a.data() + a.size());
my_func(std::begin(array), std::end(array));
my_func(ptr, ptr + numElements);
传递两个 迭代器(通用或其他)的好处是您不必将整个容器传递给算法。