如何使用自动声明数组 [英] How to declare array with auto

查看:76
本文介绍了如何使用自动声明数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在玩auto,我注意到在大多数情况下,您可以用auto替换变量定义,然后分配类型.

I have been playing with auto and I noticed that for most cases you can replace a variable definition with auto and then assign the type.

在下面的代码中,wx是等效的(默认初始化为int,但不允许进入潜在的副本中).有没有办法声明z使其具有与y相同的类型?

In the following code w and x are equivalent (default initialized int, but lets not get into potential copies). Is there a way to declare z such that it has the same type as y?

int w{};
auto x = int{};
int y[5];
auto z = int[5];

推荐答案

TL; DR

template<typename T, int N> using raw_array = T[N];

auto &&z = raw_array<int,5>{};


您的auto z = int[5];示例与auto z = int;一样合法,这仅仅是因为类型不是有效的初始化程序.您可以这样写:auto z = int{};,因为int{}是有效的初始化程序.


Your example of auto z = int[5]; isn't legal any more than auto z = int; is, simply because a type is not a valid initializer. You can write: auto z = int{}; because int{} is a valid initializer.

一旦意识到这一点,下一次尝试将是:

Once one realizes this, the next attempt would be:

auto z = int[5]{};

请注意,您的int y[5]没有任何初始化程序.如果有的话,您可能会直接跳到这里.

Note that your int y[5] does not have any initializer. If it had then you would have jumped straight here.

不幸的是,由于晦涩的语法原因,这也不起作用.相反,您必须找到一种在初始化程序中命名数组类型的合法方法.例如,可以在初始化程序中使用typedef名称.方便的可重复使用的模板类型别名消除了每种数组类型都需要新的typedef的繁琐要求:

Unfortunately this does not work either for obscure syntax reasons. Instead you must find a legal way to name the array type in an initializer. For example, a typedef name can be used in an initializer. A handy reusable template type alias eliminates the burdensome requirement of a new typedef for every array type:

template<typename T, int N> using raw_array = T[N];

auto z = raw_array<int,5>{};


此外:您可以使用模板类型别名来修复C ++怪异的由内而外"语法,从而允许您使用此提案.

不幸的是,由于C和C ++中的设计错误会导致在帽子放下时进行数组到指针的转换,因此推导出的变量z的类型是int*而不是int[5].临时数组销毁后,结果变量将变为悬空指针.

Unfortunately due to the design bug in C and C++ which causes array-to-pointer conversions at the drop of a hat, the deduced type of the variable z is int* rather int[5]. The resulting variable becomes a dangling pointer when the temporary array is destroyed.

C ++ 14引入了decltype(auto),它使用不同的类型推导规则,可以正确推导数组类型:

C++14 introduces decltype(auto) which uses different type deduction rules, correctly deducing an array type:

decltype(auto) z = raw_array<int,5>{};

但是现在我们遇到了另一个关于数组的设计错误;它们不表现为适当的对象.您不能使用数组分配,复制构造或按值传递等.上面的代码就像是说:

But now we run into another design bug with arrays; they do not behave as proper objects. You can't assign, copy construct, do pass by value, etc., with arrays. The above code is like saying:

int g[5] = {};
int h[5] = g;

通过所有权利应该可以使用,但是不幸的是,内置数组在C和C ++中表现得异常.在我们的例子中,特定的问题是不允许数组仅具有任何类型的初始化程序.它们严格限于使用初始化程序列表.由初始化列表初始化的临时数组本身不是初始化列表.

By all rights this should work, but unfortunately built-in arrays behave bizarrely in C and C++. In our case, the specific problem is that arrays are not allowed to have just any kind of initializer; they are strictly limited to using initializer lists. An array temporary, initialized by an initializer list, is not itself an initializer list.

在这一点上,约翰尼斯·绍布(Johannes Schaub)提出了一个很好的建议,即我们可以使用临时生命周期延长.

At this point Johannes Schaub makes the excellent suggestion that we can use temporary lifetime extension.

auto &&z = raw_array<int,5>{};

不需要

decltype(auto),因为添加了&&会更改推断的类型,因此Johannes Schaub的建议适用于C ++ 11.这也避免了对数组初始化程序的限制,因为我们正在初始化引用而不是数组.

decltype(auto) isn't needed because the addition of && changes the deduced type, so Johannes Schaub's suggestion works in C++11. This also avoids the limitation on array initializers because we're initializing a reference instead of an array.

如果您希望数组从初始化程序中推断出其长度,则可以使用不完整的数组类型:

If you want the array to deduce its length from an initializer, you can use an incomplete array type:

template<typename T> using unsized_raw_array = T[];

auto &&z = unsized_raw_array<int>{1, 2, 3};


尽管上述操作可以满足您的要求,但是您可能希望完全避免使用原始数组,因为原始数组的行为不像正确的C ++对象,而且它们的行为和上面使用的技术也不清楚.


Although the above does what you want you may prefer to avoid raw arrays entirely, due to the fact that raw arrays do not behave like proper C++ objects, and the obscurity of their behavior and the techniques used above.

C ++ 11中的std::array模板的行为确实像一个适当的对象,包括赋值,可通过值传递等,并且通常在内置数组没有的情况下表现出合理而一致的行为.

The std::array template in C++11 does act like a proper object, including assignment, being passable by value, etc., and just generally behaving sanely and consistently where built-in arrays do not.

auto z = std::array<int,5>{};

但是,这样做会使您错过了让数组类型从初始化程序推断其自身长度的机会.相反,您可以编写执行推断的make_array模板函数.这是一个我尚未测试过的非常简单的版本,它没有执行您可能想要的操作,例如,验证所有参数是否为同一类型,或者让您明确指定该类型.

However, with this you miss out on being able to have the array type infer its own length from an initializer. Instead You can write a make_array template function that does the inference. Here's a really simple version I haven't tested and which doesn't do things you might want, such as verify that all the arguments are the same type, or let you explicitly specify the type.

template<typename... T>
std::array<typename std::common_type<T...>::type, sizeof...(T)>
make_array(T &&...t) {
    return {std::forward<T>(t)...};
}

auto z = make_array(1,2,3,4,5);

这篇关于如何使用自动声明数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆