Sign in to follow this  
Rattrap

Operator Overloading with Templates

Recommended Posts

C++ I am trying to write a overloaded << operator for a templated class's smart pointer (aka the operator << function will take the smart pointer as a parameter, not the actual class). In my code I use the loki smart pointers, so that is what the example will reflect. Really about any could be substituted in. The code below is an example. The code it is derived from has many depenancies and would be difficult to post. The original code does compile, but the operator << is never called when debugging. This was all typed it at work, so the example hasn't been tested in a compiler.
namespace Foo
{
template <typename ThreadPolicy>
class CBar
{
    public:
        typedef Loki::SmartPtr<CBar<ThreadPolicy> > Bar;  //  A typedef for the pointer.  This makes it a little easier because of the template when working with other classes.

        CBar() {}
        ~CBar() {}
};
}

template <typename ThreadPolicy>
std::ostream& operator << (std::ostream& lhs, const typename Foo::CBar<ThreadPolicy>::Bar rhs)
{
    lhs << "Got here";

    return lhs;
}

struct SingleThreadPolicy
{
};

int main(void)
{
    // I know its a little convoluted
    Foo::CBar<SingleThreadPolicy>::Bar pBar = new Foo::CBar<SingleThreadPolicy>();

    std::cout << pBar;

    return 0;
}



As I said before the code compiles, but when I try to call the function, what I end up getting printed is just the number 1. Best of my knowledge, the Loki Smart Pointer doesn't have the << operator overloaded. [edit] Added return 0; to main(). Corrected Typedef to use CBar and not Foo. [Edited by - Rattrap on May 25, 2007 10:45:23 AM]

Share this post


Link to post
Share on other sites
 Foo::CBar<SingleThreadPolicy>::Bar pBar = new Foo::CBar<SingleThreadPolicy>();


This is weird. What is pBar, pointer or value?

Because of you allocated it with new, then the next line should be:
std::cout << * pBar;


But I don't see how this could compile in the first place.

Share this post


Link to post
Share on other sites
See the class declaration. There is a typedef that defines Bar. Because it is a typedef, you can reference it like a variable type, thus



|- Namespace Foo
| |- Templeted Class CBar
| | |- Template Paramter
| | | |- Typedefed SmartPointer to the class (so it adapts to the template paramter
V V V V
Foo::CBar<SingleThreadPolicy>::Bar pBar;




So pBar is a Smart Pointer to the CBar class that always matches the type used with the template paramter. Like I said, it looks a little convoluted, but the system I use stores a lot of strong and weak pointers and this helps define them in a single place, making it easier to change them if need be, instead of having to change them in a lot of places or using #define Macros.

So what I'm trying to do is to write a templated << operator function that will accept any templated version of CBar's Smart Pointer, so I don't have to clutter up the actual usage code anymore with the deferencing using the *. (A lot of the usage clutter goes away when adding another typedef in the code calling the functions. I know it looks a little convoluted, but it works really well in practice and allows for the use of any Threading library that adapts to the way the template policy is expecting. It also allows for a single threaded version which will optimize away the lock and unlock functions).

Share this post


Link to post
Share on other sites
Perhaps the pointer is being implicitly converted to a boolean and then output as that instead of finding your overload? Try commenting your overload out and see what happens.

Share this post


Link to post
Share on other sites
This is actually one of the more annoying things in C++, to give the short version the compiler cant deduce the type of a template paramater from the type of a dependent type. What that means is because Bar is a member type of CBar<ThreadPolicy> the compiler cant deduce the type of ThreadPolicy since it only knows the type of Bar.

Share this post


Link to post
Share on other sites
That makes some sense. So probably the only way to actual do this is to force the use of the * operator (and by force I mean just eliminate the pointer version of the operator).

And the bool conversion makes a little sense now that I think about it, since I know the pointers have the capacity to compare to others pointers and values.

Share this post


Link to post
Share on other sites
I moved the operators inside the declerations and made them class friends and it seemed to solve the problem.


namespace Foo
{
class CBar
{
public:
...
friend std::ostream& operator << (std::ostream& lhs, Bar rhs)
{
lhs << "Got here";

return lhs;
}
friend std::wostream& operator << (std::wostream& lhs, Bar rhs)
{
lhs << L"Got here";

return lhs;
}
};
}




The output is as expect, prints "Got here".

Thanks for the help.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this