C++模板中允许将'std::vector < T>&amp;'压缩为'T&amp;'吗?

uz75evzq  于 2023-05-20  发布在  其他
关注(0)|答案(1)|浏览(114)

我一直在使用下面的print_vector重载来打印出输入数组([1])的元素。

//////[1]///////
template<typename T>
void print_vector(T& vec) { // this function is for lagacy arrays in C/C++
                            // e.g. int x[3] = {1,2,3};

  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

template<typename T>
void print_vector(std::vector<T>& vec) {
  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

template<typename T>
void print_vector(thrust::host_vector<T>& vec) {
  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

template<typename T>
void print_vector(thrust::device_vector<T>& vec) {
  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

我喜欢这个的原因是,它似乎需要每个函数的“两个”类型-例如,std::vectorT的第二个。
但是我注意到下面的函数[2]可以单独为所有类型的输入执行所需的功能。

//////[2]///////

template<typename T>
void print_vector(T& vec) {
  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

乍看之下,它似乎将两种类型过度压缩为一个T,因此我认为这应该是类似于

//////[3]///////

template<typename T1, typename T2>
void print_vector(T1<T2>& vec) {
  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

在C中使用[2]函数来表示[1]中的函数重载是标准的吗?还是说[2]工作正常是一种巧合?
事实上,我仍然感到困惑的是,ranged-for for (const auto& elem : vec) {}适用于传统的C/C
数组。当我搜索ranged-for时,我发现了这个句子-"defined as anything that you can iterate through—for example, std::vector, or any other C++ Standard Library sequence whose range is defined by a begin() and end()"。虽然指针和迭代器非常相似,但它们并不相同,并且lagacy数组没有可以通过开始()和end()访问的“迭代器”,但仍然可以进行ranged-for工作。为什么?

已添加

感谢273 K,我觉得我越来越接近,但仍然不能得到一些积分。
例如,下面的代码在注解了vec.begin()部分后可以正常工作。

template<typename T>
void print_vector(T& vec) {
  //std::cout << vec.begin() << std::endl;
  std::cout << "- print vector" << std::endl;
  for (const auto& elem : vec) {
    std::cout << elem << std::endl;
  }
}

int main(void) {

  int x[5] = {1,2,3,4,5};
  print_vector(x);

  return 0;
}

但是当我打开注解行时,我在编译过程中遇到了以下错误。

main.cu(12): error: expression must have class type but it has type "int *"
          detected during instantiation of "void print_vector(T &) [with T=int [5]]"

所以,你能不能再解释一下你的话-“There are common std::开始(c)and std::end(c)for all containers and T(&)[N].”?

shyt4zoc

shyt4zoc1#

这是另一种解释方式。基于范围的for循环的存在仅仅是为了让你在不需要索引、指针或迭代器的值的情况下编写更简单的循环。通过std::开始和std::end抽象的魔力,您的示例本质上与this code相同:

#include <iostream>

void print_vector(int (&vec)[5]) {
  for (const int* elem = vec; elem != vec + 5; ++elem) {
    std::cout << *elem << std::endl;
  }
}

int main() {
  int x[5] = {1,2,3,4,5};
  print_vector(x);
}

它看起来像是C和C的混合体。虽然C允许你创建对C风格数组的引用,但这些数组没有成员函数,因为这在C中并不是一件真正的事情。因此,当您尝试调用一个类型时,C样式数组会做它最擅长的事情,并隐式地转换为指针,但指针仍然不是类类型,因此编译失败。

相关问题