繁体   English   中英

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

[英]Initializing a vector of auto (unknown) type inside a template function in C++

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

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

你不能使用autostd::vector 您可以使用std :: iterator_traits

std::vector<typename std::iterator_traits<Iter>::value_type> temp(size);

如果你有一个兼容C ++ 17的编译器,你可以从类模板参数推导中获益。

因此,除非您有特定的理由用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);

就像乔纳森的回答一样

你可能正在寻找类似的东西

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

演示

auto不起作用的原因是因为在该上下文中不允许它。 您可能不会提供auto代替模板参数。 当您希望编译器自动推导出模板参数时,正确的操作方法是根本不提供参数。 但是,在这种情况下,编译器无法推断出该类型应该是什么。 必须明确提供类型。

有很多方法可以找出你的矢量的正确类型。 您可以使用std::iterator_traits获取有关迭代器的信息,包括它引用的值的类型。 您将使用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;
}

我想指出,没有理由检查0个尺寸范围。 它会正确返回一个空向量。

您还可以通过利用std::vector具有接受一对迭代器和范围副本的构造函数来简化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);
}

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

const vector<typename iterator_traits<Iter>::value_type> temp(beg, end);

实例

该类型未知是不正确的。 您要创建的矢量类型与Iter相同。

刚刚获得iter基本类型或者使用decltype或使用迭代器类型特点如下:

  • decltype - > 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>...

我会解决这个问题,而不是你的问题似乎要求的。

首先,我发现范围是比采用两个迭代器更好的基本类型。 这两个迭代器是耦合的,它们应该是一个参数。 范围是两个迭代器的简单结构,具有一些实用方法:

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正确地将begin end迭代器连接在一起。

现在

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM