我有一个模板函数,我想在其中生成一个未知类型的向量。我试图让它自动化,但编译器说它是不允许的。
模板函数获取迭代器或指针,如后面的main函数中的测试程序中所示。如何解决问题?
template<class Iter>
auto my_func(Iter beg, Iter end)
{
if (beg == end)
throw domain_error("empty vector");
auto size = distance(beg, end);
vector<auto> temp(size); // <--HERE COMPILER SAYS CANNOT BE AUTO TYPE
copy(beg, end, temp->begin);
.
.
return ....
}
int main()
{
int bips[] = {3, 7, 0, 60, 17}; // Passing pointers of array
auto g = my_func(bips, bips + sizeof(bips) / sizeof(*bips));
vector<int> v = {10, 5, 4, 14}; // Passing iterators of a vector
auto h = my_func(v.begin(), v.end());
return 0;
}
答案 0 :(得分:42)
您无法使用std::vector
auto
。您可以改为使用std::iterator_traits:
std::vector<typename std::iterator_traits<Iter>::value_type> temp(size);
答案 1 :(得分:32)
如果您有兼容C ++ 17的编译器,则可以从class template argument deduction获利。
因此,除非您有特定的理由用std::copy
填充向量,否则您可以编写如下代码:
template<class Iter>
auto my_func(Iter beg, Iter end)
{
if (beg == end)
throw domain_error("empty vector");
vector temp(beg, end);
// do the remaining stuff
return ....
}
如果您的编译器没有此功能,那么我会投票
vector<typename iterator_traits<Iter>::value_type> temp(beg, end);
答案 2 :(得分:7)
答案 3 :(得分:3)
typename std::iterator_traits<Iter>::value_type
不起作用的原因是因为在该上下文中不允许这样做。您可能不会提供#include <algorithm>
#include <iterator>
#include <stdexcept>
#include <vector>
template<class Iter>
auto my_func(Iter beg, Iter end)
{
if (beg == end)
throw std::domain_error("empty vector");
auto size = std::distance(beg, end);
using t_value = typename std::iterator_traits<Iter>::value_type;
std::vector<t_value> temp(size);
std::copy(beg, end, temp.begin());
return temp;
}
int main()
{
int bips[] = { 3,7,0,60,17 };//Passing pointers of array
auto g = my_func(bips, bips + sizeof(bips) / sizeof(*bips));
std::vector<int> v = { 10,5,4,14 };//Passing iterators of a vector
auto h = my_func(v.begin(), v.end());
return 0;
}
来代替模板参数。当您希望编译器自动推导出模板参数时,正确的操作方法是根本不提供参数。但是,在这种情况下,编译器无法推断出该类型应该是什么。您必须明确提供类型。
有很多方法可以找出你的矢量的正确类型。您可以使用std::iterator_traits
获取有关迭代器的信息,包括它所引用的值的类型。您可以使用my_func
。
template<class Iter>
auto my_func(Iter beg, Iter end)
{
using t_value =typename std::iterator_traits<Iter>::value_type;
return std::vector<t_value>(beg, end);
}
我想指出,没有理由检查0个尺寸范围。它会正确返回一个空向量。
您还可以利用std::vector
具有接受一对迭代器和范围副本的构造函数的事实来简化{{1}}的主体。
{{1}}
答案 4 :(得分:2)
答案 5 :(得分:1)
不知道该类型是不正确的。您要创建的矢量类型与Iter
相同。
只需使用iter
或使用迭代器类型特征获取decltype
基础类型,如下所示:
decltype
- &gt; std::vector<typename remove_reference<decltype(*beg)>::type> temp(beg, end);
iterator type trait
如下
using Type = std::iterator_traits<Iter>::value_type;
std::vector<Type>...
答案 6 :(得分:0)
我解决这个问题的方式与您提出的问题略有不同。
首先,我发现范围是比采用两个迭代器更好的基本类型。这两个迭代器是耦合的,它们应该是一个参数。范围是两个迭代器的简单结构,有一些实用方法:
template<class It>
struct range_t:
std::iterator_traits<It>
{
It b{}, e{};
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
auto size() const { return std::distance(begin(), end()); }
// etc
range_t()=default;
range_t(range_t const&)=default;
range_t(range_t &&)=default;
range_t& operator=(range_t const&)=default;
range_t& operator=(range_t &&)=default;
};
template<class It>
range_t<It> make_range( It s, It f ) { return {std::move(s), std::move(f)}; }
range_t
正确地将开始结束迭代器连接在一起。
现在
template<class Range>
auto my_func(Range&& range) {
// todo
}
template<class Iter>
auto my_func(Iter beg, Iter end)
{
return my_func(make_range(std::move(beg), std::move(end)));
}
是第一步。或者完全消除双迭代器版本,并期望调用者为你打包迭代器。
template<class Range>
auto my_func(Range&& range) {
if (range.empty())
throw domain_error("empty vector");
// todo
}
好的,现在你要这样做:
auto size = range.size();
vector<auto> temp(size);//<--HERE COMPILER SAYS CANNOT BE AUTO TYPE
copy(range.begin(), range.end(), temp->begin);
但这是一项常见的操作。所以我们写它的范围:
template<class Range>
auto as_vector( Range const& r ) {
using value_type = typename Range::value_type;
std::vector<value_type> v( range.begin(), range.end() );
return v;
}
给我们:
template<class Range>
auto my_func(Range&& range) {
if (range.empty())
throw domain_error("empty vector");
auto v = as_vector(range);
// ...
return ...;
}
我们已将您的问题分解为具有意义的简单原语,并将实现复杂性转移到这些原语中。 my_func
的“业务逻辑”不再关心您将范围转换为矢量所采取的步骤。
这使您的my_func
更多可读,只要您确信as_vector(range)
实际上将该范围作为向量返回。