对于循环索引类型推演的最佳实践 [英] For loop index type deduction best practice

查看:110
本文介绍了对于循环索引类型推演的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,我有一个类型为size()的容器c,我想遍历此容器,同时跟踪每个项目的索引:

Let's say, I have a container c of a type that provides a size() method and I want to loop over this container while keeping track of each item's index:

for (/*TODO*/ i = 0; i < c.size(); i++) {...}

在C ++ 11后的世界中,自动类型推导很好地解决了很多问题.我们应该用什么代替上面的TODO?不管size()的类型是什么,对我来说唯一正确的是以下内容:

In a post-C++11 world, where automatic type deduction solves so many problems nicely. What should we use in place of the TODO above? The only thing that seems correct to me, no matter what the type of size() is, is the following:

for (decltype(c.size()) i = 0; i < c.size(); i++) {...}

但是,这似乎过于冗长,在我看来,这对可读性没有帮助.

But this seems overly verbose and ,in my opinion, doesn't help readability.

另一个解决方案可能是:

Another solution might be this:

for (auto end = c.size(), i = 0; i < end; i++) {...}

但这也无助于可读性,当然也没有与原始代码段相同的语义.

But this doesn't help readability either and, of course, doesn't have the same semantics as the original snippet.

所以,我的问题是:仅给出索引限制的类型,推论循环索引变量类型的最佳方法是什么?

So, my question is: what is the best way to deduce the type of a loop index variable, given only the type of the index' limit.

推荐答案

文本中 first 问题的简短答案:您应将/*TODO*/替换为unsignedstd::size_t或类似的意思是:不要打扰类型,只需选择适合任何合理容器尺寸的类型即可.

Short answer to the first question in your text: You should replace the /*TODO*/ by unsigned, std::size_t or something similar, meaning: don't bother deducing the type, just pick a type suitable for any reasonable container size.

这将是一个无符号的,相当大的类型,因此编译器不会因为可能的精度损失而大喊大叫.在上面的注释中,您写道size_t不能保证很好地替代decltype(c.size()),但是尽管并非不可能实现索引不兼容size_t的容器,这样的indizes肯定不是数字(因此与i = 0不兼容),并且容器也不会具有size方法. size()方法暗含一个非负整数,并且由于size_t是为精确地计算这些数字而设计的,因此拥有一个无法用其表示的大小的容器几乎是不可能的.

This would be an unsigned, reasonably large type so the compiler is not tempted to yell at you beacuse of possible precision losses. In the comments above you write that size_t is not guaranteed to be a good replacement to decltype(c.size()), but while it is not impossible to implement a container that has an index incompatible to size_t, such indizes would most surely not be numbers (and thus incompatible to i = 0), and the containers would not have a size method either. A size() method implies a nonnegative integral, and since size_t is designed for exact those numbers, it will be close to impossible to have a container of a size that cannot be represented by it.

您的第二问题旨在介绍如何推导类型,您已经提供了最简单但不完美的答案.如果您想要的解决方案不像decltype那样冗长,而又不像auto end那样令人惊讶,则可以在一些实用程序头中为起始索引定义模板别名和生成器函数:

Your second question aims at how to deduce the type, and you already have provided the easiest, yet imperfect answers. If you want a solution that is not as verbose as decltype and not as surprising to read as auto end, you could define a template alias and a generator function for the starting index in some utility header:

template <class T> 
using index_t = decltype(std::declval<T>().size());

template <class T, class U>
constexpr index_t<T> index(T&&, U u) { return u; }

//and then in the actual location of the loop:
for (auto i = index(c,0); i < c.size(); ++i) {...}
//which is the same as
for (auto i = index_t<std::vector<int>>(0); i < c.size(); ++i) {...}

如果您要使用更通用的索引类型,例如对于没有size方法的数组和类,它将变得更加复杂,因为模板别名可能不是专门的:

If you want to have a more general index-type, e.g. for arrays and classes that don't have a size method, it gets a bit more complicated, because template aliases may not be specialized:

template <class T>
struct index_type {
  using type = decltype(std::declval<T>().size());
};

template <class T>
using index_t = typename index_type<T>::type;

template <class T, class U>
constexpr index_t<T> index(T&&, U u) { return u; }

//index_type specializations
template <class U, std::size_t N>
struct index_type<U[N]> { 
  using type = decltype(N); 
};

template <>
struct index_type<System::AnsiString::AnsiString> { //YUCK! VCL!
  using type = int; 
};

但是,仅在少数情况下,这实际上是很多东西,您实际上需要一个索引,而简单的foreach循环是不够的.

However, this is a lot of stuff just for the few cases where you actually need an index and a simple foreach loop is not sufficient.

这篇关于对于循环索引类型推演的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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