Consider:
#include <iostream>
#include <vector>
class A
{
public:
typedef bool TAll;
static TAll All;
typedef std::vector<int> TVec;
static TVec m_sVec;
static TVec::iterator begin() { return m_sVec.begin(); }
static TVec::iterator end() { return m_sVec.end(); }
};
A::TVec A::m_sVec;
A::TAll A::All;
A::TVec::iterator begin(A::TAll& all) { return A::begin(); }
A::TVec::iterator end(A::TAll& all) { return A::end(); }
int _tmain(int argc, _TCHAR* argv[])
{
A::m_sVec.push_back(1);
A::m_sVec.push_back(2);
A::m_sVec.push_back(3);
for (auto a : A::All) {
//for (auto a = begin(A::All); a != end(A::All); a++) {
std::cout << a << std::endl;
}
return 0;
}
The version with the range based for loop (so this code as-is) gives me the following error in MSVC2013:
1><snip>: error C3312: no callable 'begin' function found for type 'A::TAll'
1><snip>: error C3312: no callable 'end' function found for type 'A::TAll'
GCC (4.8.3) says (last two lines):
/usr/include/c++/4.8.3/initializer_list:99:5: note: template<class _Tp> constexpr cons
t _Tp* std::end(std::initializer_list<_Tp>)
end(initializer_list<_Tp> __ils) noexcept
^
/usr/include/c++/4.8.3/initializer_list:99:5: note: template argument deduction/subs
titution failed:
main.cpp:31:18: note: mismatched types 'std::initializer_list<_Tp>' and 'bool'
for (int a : A::All) {
The 'normal' for loop that uses the functions (the one that is commented out) works (well, after dereferencing 'a' inside the loop of course); it is my understanding of the standard and the Stroustroup that they should be equivalent. But I guess not. So what is the problem here? Thanks.
Per C++11 [stmt.ranged]/1, your loop:
for (auto a : A::All) {
std::cout << a << std::endl;
}
is equivalent to:
{
auto && __range = (A::All);
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
auto a = *__begin;
{
std::cout << a << std::endl;
}
}
}
where the determination of the expressions begin-expr and end-expr depends on the type _RangeT of the initializer expression A::All (bool in this case):
- if
_RangeTis an array type, ...- if
_RangeTis a class type, ...- otherwise, begin-expr and end-expr are
begin(__range)andend(__range), respectively, wherebeginandendare looked up with argument-dependent lookup (3.4.2) [emphasis added]. For the purposes of this name lookup, namespacestdis an associated namespace.
Since bool is neither an array or class type, the third bullet applies; the expressions are begin(__range) and end(__range), but begin and end are resolved using ADL with std as an associated namespace. Per 3.4.2 [basic.lookup.argdep]/2:
For each argument type
Tin the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set. [emphasis added] The sets of namespaces and classes are determined in the following way:
- If T is a fundamental type, its associated sets of namespaces and classes are both empty.
- ...
So begin and end are looked up only in the std namespace, where several declarations are found, but none that can accept an argument of type bool. The program is ill-formed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With