在C ++中初始化模板函数内的auto(未知)类型的向量

时间:2017-07-20 14:09:34

标签: c++ templates stl iterator

我有一个模板函数,我想在其中生成一个未知类型的向量。我试图让它自动化,但编译器说它是不允许的。

模板函数获取迭代器或指针,如后面的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;
}

7 个答案:

答案 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);

喜欢in Jonathan's answer

答案 2 :(得分:7)

您可能正在寻找类似

的内容
std::vector<typename std::remove_reference<decltype(*beg)>::type> temp(beg, end);

Demo

答案 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)

您可以使用iterator_traits提取指针/ auto的类型信息。 value_type是您感兴趣的特定特征,因此您可以这样做:

auto

Live Example

答案 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)实际上将该范围作为向量返回。