我想用一个参数编写一个C ++函数,以便可以传递以下任何一种类型:
std::vector<int>
std::array<int>
int array[numElements]
int *ptr = new int[numElements]
etc
模板是实现这一目标的最佳方法吗?
答案 0 :(得分:6)
如果您希望能够做func(v)
,就不能,因为我无法想到您的函数可以推断出动态分配的int[numElements]
的大小。
您可以用一个正向迭代器来包装它,这是一种好方法,也就是说,如果您只需要一个一个地迭代一个项目,因为对std::list
之类的某些容器来说,随机访问是非常不好的。 / p>
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的更改,它也可以通过直接传递原始数组而不是两个指针来工作(但仍不适用于动态分配的数组)。
答案 1 :(得分:3)
模板是实现这一目标的最佳方法吗?
这取决于。如果您要编写的函数包含在标头中,因此可以在以后用于进一步的编译,那么-是的,可能是:
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?
此函数将能够按原样使用几乎所有变量:std::vector
,std::array
和普通(大小)数组可以在不使用额外语法的情况下进行传递。但是,对于指针,您将需要调用类似f(gsl::make_span{ptr, numElements})
的东西。
PS-标准库中非常常见的第三个选项是将插入符而不是容器作为参数。这还需要模板,因此类似于第一个选项。
答案 2 :(得分:2)
不能将所有列出的类型都放在一个功能模板中。但是,您可能会有函数模板重载,这将解决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类型数组。
答案 3 :(得分:1)
span
似乎是您想要的。等待C ++ 20 :-)或使用GSL中的span。参见What is a “span” and when should I use one?
。下面的示例。
#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;
}
答案 4 :(得分:0)
如果它们都使用int
,那么您可以简单地接受开始和结束指针。您可以在其上使用标准的算法,因为 pointers 是 iterators 。
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);
传递两个 iterators (泛型或其他)的好处是您不必将整个容器传递给算法。