nested template class, overloaded operator not found

Started by
4 comments, last by SiS-Shadowman 14 years, 2 months ago
I've written a small test that demonstrates the problem. I've got a template for a class (A) that contains a template for a nested class (B). I want to define stream operators for both classes, however the compiler is never able to find the one I've defined for A::B:

template <typename T>
class A
{
public:

	template <typename O>
	class B
	{};
};

template <typename t>
class C
{};



template <typename Char, typename Traits, typename T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const A<T>&)
{
	return stream << "A!";
}

template <typename Char, typename Traits, typename T, typename O>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const typename A<T>::B<O>&)
{
	return stream << "B in A!";
}

template <typename Char, typename Traits, typename T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const C<T>&)
{
	return stream << "C!";
}



int main(int argc, char* argv[])
{
	std::cout << A<int>() << std::endl;
	std::cout << C<int>() << std::endl;
	std::cout << A<int>::B<int>() << std::endl;
}

Both cout << A<int>() and cout << C<int>() compile, however the compiler claims that there is no operator that takes a right-hand A<T>::B<O> operand. Is this an error on my part and is there something I can do about it? I think I need that behaviour because I'm writing a small generic class that stores sequences of elements and that provides views on that sequence (the view class is the nested one). I'm using Visual Studio 2008 without any SP.
Advertisement
I find the token "typename" in line
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const typename A<T>::B<O>&)
to be very suspicious; you could try removing it.
It raises an error when I do not add "typename", because the compiler doesn't know B is a type without it.
Quote:
warning C4346: 'A<T>::B<O>' : dependent name is not a type prefix with 'typename' to indicate a type
error C2061: syntax error : identifier 'B'
Changing

std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const typename A<T>::B<O>&)


to

std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const typename A<T>::template B<O>&)


would solve one part of the problem. The other one is that apparently it is not possible to deduce T this way. I succeeded by circumventing the nesting - just do an empty derivation of a base class, like this:

template <typename O>class B1{};template <typename T>class A{public:	template <typename O>	class B: public B1 < O >	{};};template <typename t>class C{};template <typename Char, typename Traits, typename T>std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const A<T>&){	return stream << "A!";}template <typename Char, typename Traits, typename T>std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const B1<T>&){	return stream << "B in A!";}template <typename Char, typename Traits, typename T>std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const C<T>&){	return stream << "C!";}int main(int argc, char* argv[]){	std::cout << A<int>() << std::endl;	std::cout << C<int>() << std::endl;	std::cout << A<int>::B<int>() << std::endl;}


Note B1 and B. B is essentially just a "template typedef". A proper template typedef does not exist in C++98 (but will exist in C++0x), so I just do an "empty derivation", e.g. the derived class does not really add anything to the base class functionality.
~dv();
AFAIK, this is because the compiler is unable to deduce the template parameters for your operator<< for A<T>::B<O>s. This is because the type T is used in a non-deduced context, as it is used as part of a nested type name.

So if you explicitly give the call its template parameters, it works:

template <typename T, typename O, typename Char, typename Traits> // note orderstd::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& stream, const typename A<T>::B<O>&){	return stream << "B in A!";}// ...::operator<< <int, int>(std::cout, A<int>::B<int>()); // ok


Not entirely sure though, I'll leave it to the true C++ wizards to quote you C++ standard references and give a conclusive answer :)
Thanks for the answer.
I'll try that :)

This topic is closed to new replies.

Advertisement