How to pass this template template argument? (MSVC++ 8 error C3200)

  • Thread starter Niels Dekker - no reply address
  • Start date
N

Niels Dekker - no reply address

The following attempt to pass my template "Base" as a template template
argument was rejected by Microsoft VC++ 8.0 (2005), while it still works
on VC++ 7.1 (2003). Is it correct C++? And is there a workaround?

template <typename T> class Base
{
};
template <typename U, template <typename> class TempTemp>
class Derived;

template <typename V>
class Derived<V, Base> : public Base<V>
{
public:
template <typename W> void Fun(Derived<W, Base>&) // <-- error!?!
{
}
};

MSVC++ 8.0 says about Fun(Derived<W, Base>&):
error C3200: 'Base<T>' : invalid template argument for template
parameter 'TempTemp', expected a class template
see reference to class template instantiation 'Derived<V,Base>' being
compiled


Kind regards,

Niels Dekker
www.xs4all.nl/~nd/dekkerware
 
V

Victor Bazarov

Niels said:
The following attempt to pass my template "Base" as a template
template argument was rejected by Microsoft VC++ 8.0 (2005), while it
still works on VC++ 7.1 (2003). Is it correct C++? And is there a
workaround?

template <typename T> class Base
{
};
template <typename U, template <typename> class TempTemp>
class Derived;

template <typename V>
class Derived<V, Base> : public Base<V>
{
public:
template <typename W> void Fun(Derived<W, Base>&) // <-- error!?!
{
}
};

MSVC++ 8.0 says about Fun(Derived<W, Base>&):
error C3200: 'Base<T>' : invalid template argument for template
parameter 'TempTemp', expected a class template
see reference to class template instantiation 'Derived<V,Base>' being
compiled

I just added this:

int main()
{
Derived<int,Base> di;
Derived<char,Base> dc;
di.Fun(dc);
}

And compiled it successfully with VC++ v8.0.

Please next time post the _complete_ code if you want us to be able
to help you with any particular problem.

V
 
J

John Carson

Victor Bazarov said:
I just added this:

int main()
{
Derived<int,Base> di;
Derived<char,Base> dc;
di.Fun(dc);
}

And compiled it successfully with VC++ v8.0.


Strange. It won't compile for me on either VC++ Express 2005 or a Release
Candidate of VS Team System.
 
J

John Carson

Niels Dekker - no reply address said:
The following attempt to pass my template "Base" as a template
template argument was rejected by Microsoft VC++ 8.0 (2005), while it
still works on VC++ 7.1 (2003). Is it correct C++? And is there a
workaround?

template <typename T> class Base
{
};
template <typename U, template <typename> class TempTemp>
class Derived;

template <typename V>
class Derived<V, Base> : public Base<V>
{
public:
template <typename W> void Fun(Derived<W, Base>&) // <-- error!?!
{
}
};

The workaround is to qualify Base with ::, so that it becomes:

template <typename W> void Fun(Derived<W, ::Base>&)
{
}

As for whether your original code is valid C++, I am inclined to think that
it is but I wouldn't bet my life on it. The strongest indication that the
original code is valid is that Comeau compiles it without complaint.

I believe what is happening is the following. VC++ 8 is reading Base as
Base<V>. In the following simpler example, that would be correct:

template <class V>
class Base
{
Base b; // read this as Base<V>
};

If you wanted to refer to the template Base inside Base, then you could use
::Base.

Where VC++ 8 appears to have gone subtlely wrong is in treating Base in
Derived the same way as it would treat Base in Base. Because Base is a
dependent base (i.e., it depends on V), two phase lookup (as I understand
it) says that it should not be looked up until the template is instantiated.
Thus Base<V> is not seen when Fun is defined, with the result that Base is
treated as a template, so the code compiles. VC++ does not support two phase
lookup, so it does see Base<V> when Fun is defined and hence gives an
error...or at least I think that is the explanation.
 
V

Victor Bazarov

John said:
Strange. It won't compile for me on either VC++ Express 2005 or a
Release Candidate of VS Team System.

Compiled for me on Express 2005. Are you sure you used the same code?
-------------- this is from your post
template<typename T> class Base
{
};

template<typename U, template<typename> class TempTemp> class Derived;

template<typename V> class Derived<V, Base> : public Base<V>
{
public:
template <typename W> void Fun(Derived<W, Base>&) // <-- error!?!
{
}
};
// -------------- this I added...
int main()
{
Derived<int,Base> di;
Derived<char,Base> dc;
di.Fun(dc);
}
 
J

John Carson

Victor Bazarov said:
Compiled for me on Express 2005. Are you sure you used the same code?
-------------- this is from your post
template<typename T> class Base
{
};

template<typename U, template<typename> class TempTemp> class
Derived;
template<typename V> class Derived<V, Base> : public Base<V>
{
public:
template <typename W> void Fun(Derived<W, Base>&) // <-- error!?!
{
}
};
// -------------- this I added...
int main()
{
Derived<int,Base> di;
Derived<char,Base> dc;
di.Fun(dc);
}


Straight copy and paste from what you just posted above and it won't compile
(and my first error is the one reported by the OP).
 
J

John Carson

Victor Bazarov said:
Compiled for me on Express 2005. Are you sure you used the same code?


You are using /Za aren't you? It seems that makes the difference. (It would
be nice to think that this difference is a direct result of /Za giving more
compliant behaviour. I have a suspicion, however, that it is actually a
result of /Za being less tested, so that the 2003 behaviour wasn't changed.)
 
V

Victor Bazarov

John said:
You are using /Za aren't you? It seems that makes the difference.

Yes, most certainly. If "language extensions" are disabled, I get to
check the actual compliance (and it's not bad). Since I am not usually
compiling any Windows API/SDK (which needs extensions), /Za is it.
(It
would be nice to think that this difference is a direct result of /Za
giving more compliant behaviour. I have a suspicion, however, that it
is actually a result of /Za being less tested, so that the 2003
behaviour wasn't changed.)

I don't understand this, sorry. Perhaps further discussions on VC++
should continue in 'microsoft.public.vc.language'...

V
 
J

John Carson

Victor Bazarov said:
Yes, most certainly. If "language extensions" are disabled, I get to
check the actual compliance (and it's not bad). Since I am not
usually compiling any Windows API/SDK (which needs extensions), /Za
is it.

I don't understand this, sorry. Perhaps further discussions on VC++
should continue in 'microsoft.public.vc.language'...

On further investigation, I appear to be wrong. Consider this simpler case:

template<class T>
struct Base
{
Base(T arg) : t(arg)
{}
T t;
};

template<class T>
struct Derived : Base<T>
{
Derived(T arg) : Base(arg) // compilation failure here
{}
};

int main()
{
Derived<int> d(235);
}

This (correctly) fails to compile with /Za, but will compile without it.

The change needed to get it to compile with (or without) /Za is to change
the Derived constructor so that Base has a template argument:

Derived(T arg) : Base<T>(arg)
{}

For the original

Derived(T arg) : Base(arg)
{}

we get the following error message with /Za, among others:

'Derived<T>' : illegal member initialization: 'Base' is not a base or member

Thus /Za is controlling whether or not Base is interpreted as Base<T> within
Derived, which is the same issue as in the OP's code. However, I have been
unable to find any documentation of this effect of /Za.
 
N

Niels Dekker - no reply address

Thanks, Victor and John, you really helped me out!

Victor said:
I just added this: [...]
And compiled it successfully with VC++ v8.0.
Please next time post the _complete_ code if you want us to be
able to help you with any particular problem.

Sorry for not including my -empty- main() function. I hadn't realized
that this compile error only occurs when Microsoft language extensions
are enabled.

John said:
If you wanted to refer to the template Base inside Base, then you
could use ::Base.

Apparently I can also use ::Base inside Derived, and this will fix my
problem! The following compiles for MSVC++ 8 (both with and without
language extensions), as well as MSVC++ 7.1 and Comeau (online). And I
guess it's still correct C++ as well!

template <typename T> class Base
{
};
template <typename U, template <typename> class TempTemp>
class Derived;

template <typename V>
class Derived<V, Base> : public Base<V>
{
public:
template <typename W> void Fun(Derived<W, ::Base>&) // <-- okay!
{
}
};

int main()
{
}


Thanks again,

Niels Dekker
www.xs4all.nl/~nd/dekkerware
 
J

John Carson

Niels Dekker - no reply address said:
Thanks, Victor and John, you really helped me out!

Victor said:
I just added this: [...]
And compiled it successfully with VC++ v8.0.
Please next time post the _complete_ code if you want us to be
able to help you with any particular problem.

Sorry for not including my -empty- main() function. I hadn't realized
that this compile error only occurs when Microsoft language extensions
are enabled.

John said:
If you wanted to refer to the template Base inside Base, then you
could use ::Base.

Apparently I can also use ::Base inside Derived, and this will fix my
problem!


I know. I said that in my post.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,001
Messages
2,570,254
Members
46,850
Latest member
VMRKlaus8

Latest Threads

Top