Re: class inside of template puzzler
On 22 Sep., 23:42, Jason Turner <lefti...@gmail.com> wrote:
#include <map>
I expect here one additional include:
#include <string>
template<class P1>
struct T
{
struct T2
{
T2() {}
};
T()
{
std::map<std::string, T2> m;
std::map<std::string, T2>::iterator itr1 = m.begin();
//error: expected `;' before 'itr'
std::map<std::string, T::T2>::iterator itr2 = m.begin();
//type/value mismatch at argument 2 in template parameter list
for 'template<class _Key, class _Tp, class _Compare, class _Alloc>
class std::map'
// expected a type, got 'T<P1>::T2'
// template argument 4 is invalid
// expected initializer before 'itr2'
std::map<std::string, T<P1>::T2 >::iterator itr3 = m.begin();
//Same error as above
std::map<std::string, T<int>::T2 >::iterator itr4 = m.begin();
// Compiles, but not really useful
typename std::map<std::string, T2>::iterator itr5 = m.begin();
// Works as expected
}
};
int main() {}
I understand that typename is meant to be used in cases where the
compiler thinks there is an ambiguity and it does not know if you are
referring to a type or a variable. However, I don't understand why it
is is needed in the case above.
In all reclaimed cases it is indeed that the compiler cannot
know, whether
std::map<std::string, T2>::iterator
specifies a type or a non-type entity, because T2 is a
dependent type and therefore also std::map<std::string, T2>
is also type-depending. The compiler cannot foresee by the
basic language rules whether there exists a specialization
of std::map for *some special T2* which has e an iterator
that is a type. The problem would *not* exist, if T2 where
declared as completly known type, as e.g. in the following
example:
struct TBase {
struct T2
{
T2() {}
};
};
template<class P1>
struct T : TBase
{
T()
{
std::map<std::string, T2> m;
std::map<std::string, T2>::iterator itr1 = m.begin(); // OK
std::map<std::string, typename T::T2>::iterator itr2 =
m.begin(); // OK
std::map<std::string, typename T<P1>::T2 >::iterator itr3 =
m.begin(); // OK
std::map<std::string, T<int>::T2 >::iterator itr4 =
m.begin(); // OK
...
}
};
Note that I added two typename prefixes in the
expressions that define itr2 and itr3, because in
both cause the second template argument of std::map
is still type-dependent (according to the currently
valid standard ISO-14882-2003, see [temp.res]/6).
Case in point, the declaration of "m" does not need "typename."
Yes and there is never a reason for that, because
the compiler requires to see <map>, which declares
the class template std::map. Since we don't have
overloading of class templates, it is clear, that
std::map<> must always be type - independent on
it's template arguments (This does of course not
guarantee, that for every template argument of
std::map every derived expression of std::map<T, ..>
is well-formed).
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]