gpt4 book ai didi

c++ - 为什么 decltype 在这里工作,但不是 auto?

转载 作者:IT老高 更新时间:2023-10-28 22:59:26 26 4
gpt4 key购买 nike

我的代码如下:

template <typename T, typename sepT = char>
void print2d(const T &data, sepT sep = ',') {
for(auto i = std::begin(data); i < std::end(data); ++i) {
decltype(*i) tmp = *i;
for(auto j = std::begin(tmp); j < std::end(tmp); ++j) {
std::cout << *j << sep;
}
std::cout << std::endl;
}
}

int main(){
std::vector<std::vector<int> > v = {{11}, {2,3}, {33,44,55}};
print2d(v);

int arr[2][2] = {{1,2},{3,4}};
print2d(arr);

return 0;
}

如果我将 decltype 更改为 auto,它不会编译并报错(部分错误):

2d_iterator.cpp: In instantiation of ‘void print2d(const T&, sepT) [with T = int [2][2]; sepT = char]’:
2d_iterator.cpp:21:21: required from here
2d_iterator.cpp:9:36: error: no matching function for call to ‘begin(const int*&)’
2d_iterator.cpp:9:36: note: candidates are:
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/string:53:0,
from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/locale_classes.h:42,
from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/bits/ios_base.h:43,
from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ios:43,
from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ostream:40,
from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/iterator:64,

为什么会这样?

最佳答案

答案总结在一条评论中:

decltype yields int(&)[2], whilst plain auto forces a pointer conversion (same rules as template argument deduction). Just use auto&. - Xeo


@Xeo 的comment-answer 基本上说因为 auto 涉及与 template argument type deduction 相同的规则,所以 auto 推导出一个指针 (int*) 类型超出源的数组类型(i,特别是 int(&)[2])。

您的代码中有一些很棒的东西:它实际上演示了当参数是引用时模板类型推导的行为以及引用如何影响推导类型的方式。

template <typename T, typename sepT = char>
void print2d(const T &data, sepT sep = ',') {
...
}

...

int arr[2][2] = {{1,2},{3,4}};
print2d(arr);

您可以看到 data 的类型是 const T&,它是对 const T 的引用。现在,它与 arr 一起传递,其类型为 int[2][2],它是由两个 int 组成的两个数组组成的数组>s(哇!)。现在来模板参数类型推导。在这种情况下,它规定 data 是一个 referenceT 应该用参数的原始类型来推导,即 int[2][2]。然后,它将参数类型的任何限定应用于 parameter,并且 data 的限定类型是 const T&应用了 const& 限定符,因此 data 的类型是 const int (&) [2][2]

template <typename T, typename sepT = char>
void print2d(const T &data, sepT sep = ',') {
static_assert(std::is_same<T, int[2][2]>::value, "Fail");
static_assert(std::is_same<decltype(data), const int(&)[2][2]>::value, "Fail");
}

...

int arr[2][2] = {{1,2},{3,4}};
print2d(arr);

LIVE CODE

然而,if data 将是一个 non-reference,模板参数类型推导规则,如果参数的类型是数组类型(例如 int[2][2]), the array type shall "decay" to its corresponding pointer type ,从而使 int[2][2] 变成 int(*)[2] (加 const 如果参数是 const) ( fix courtesy of @Xeo ).


太棒了!我只是解释了完全不是导致错误的部分。 (而且我刚刚解释了很多模板魔法)...

... 没关系。现在到错误。但在我们走之前,请记住这一点:

auto == template argument type deduction
+ std::initializer_list deduction for brace init-lists // <-- This std::initializer_list thingy is not relevant to your problem,
// and is only included to prevent any outbreak of pedantry.

现在,您的代码:

for(auto i = std::begin(data); i < std::end(data); ++i) {
decltype(*i) tmp = *i;
for(auto j = std::begin(tmp); j < std::end(tmp); ++j) {
std::cout << *j << sep;
}
std::cout << std::endl;
}

战斗前的一些先决条件:

  • decltype(data) == const int (&) [2][2]
  • decltype(i) == const int (*) [2](参见 std::begin),它是一个指向 int[2] 的指针。

现在当你执行 decltype(*i) tmp = *i; 时,decltype(*i) 将返回 const int(&)[2] ,对 int[2] 的引用(记住单词 dereference)。因此,它也是 tmp 的类型。 您使用 decltype(*i) 保留了原始类型。

但是,当你这样做时

auto tmp = *i;

猜猜decltype(tmp)是什么:int*!为什么?因为上面所有的 babbery-blablablah,还有一些模板魔法。

那么,为什么 int* 会出错?因为 std::begin 需要一个数组类型,而不是其较小的衰减指针。因此,当 tmpint* 时,auto j = std::begin(tmp) 会导致错误。

如何解决(还有tl;dr)?

  • 保持原样。使用 decltype

  • 猜猜看。让你的 autoed 变量成为引用!

    auto& tmp = *i;

    LIVE CODE

    const auto& tmp = *i;

    如果您不打算修改 tmp 的内容。 (Greatness by Jon Purdy)


故事的寓意:一个伟大的评论可以为一个人节省一千个字。


UPDATE:const 添加到 decltype(i)decltype(*i) 给出的类型中, 因为 std::begin(data) 将返回一个 const 指针,因为 data 也是 const (fix by litb ,谢谢)

关于c++ - 为什么 decltype 在这里工作,但不是 auto?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21824013/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com