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.
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.
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) {...}
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;
};
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…