Jump to content
  • Advertisement
Sign in to follow this  
SiS-Shadowman

nested template class, overloaded operator not found

This topic is 3050 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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'

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 order
std::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 :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!