operator overload : how to take care of the "rest" ?

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

operator overload : how to take care of the "rest" ?

Post by binbinhfr » May 19th, 2019, 5:20 pm

Hi,

I needed to overload the operator<< to output tests on the console (to output a string to a wide stream), and I wonder why the following piece of code did not work the way I would like to (well infact I know, my template overloads some already declared types ;-) ) ...

Code: Select all

std::wostream& operator<<(std::wostream& ost, const char* s)
{
	return( s == nullptr ? ost : ost<< std::wstring(s, s + strlen(s)));
}

std::wostream& operator<<(std::wostream & ost, const std::string & s)
{
	return(ost << std::wstring(s.begin(), s.end()));
}

template <typename A>
std::wostream& operator<<(std::wostream& ost, const A& a)
{
	ost << "don't know how to output type [" << typeid(a).name() << "]";
	return(ost);
}
I mean, the first two functions (when alone) works fine, but I figured out that I could write some kind of an overload operator<< that would take care of all the types that I did not explicitely defined (or that are not defined in std).

Any idea on what I should do to create such a function that takes care of the remaining types ?

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: operator overload : how to take care of the "rest" ?

Post by albinopapa » May 20th, 2019, 3:10 am

Custom types or User Defined Types will need to have overloads for them as well.

What other types are you looking for?

wchar_t* and std::wstring should already be overloaded for std::wcstream.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

Re: operator overload : how to take care of the "rest" ?

Post by binbinhfr » May 20th, 2019, 7:21 am

Infact, I illustrated on this example, but my question was more general : is it possible to write an overload function or operator that takes care about all the types that have not been specifically overloaded elsewhere in the code ?

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: operator overload : how to take care of the "rest" ?

Post by albinopapa » May 20th, 2019, 9:20 am

Ok, well then no not really.

Say you have this:

Code: Select all

struct Thing1
{
   int a, b, c;
   std::string name;
};

struct Thing2
{
   Vec3f position, velocity;
   Rectf bb;
};
How are you going to have one function take care of both of these types?
The best you can do is to define overloads for them.

Code: Select all

struct Thing1
{
   int a, b, c;
   std::string name;
   friend std::wcstream& operator<<( std::wcstream& wcs, Thing1 const& thing )
   {
      wcs << thing.name << " has these values "<< "a = " << thing.a << "b = " << thing.b << "c = " << thing.c << '\n';
      return wcs;
   }
};

struct Thing2
{
   Vec3f position, velocity;
   Rectf bb;
   friend std::wcstream& operator<<( std::wcstream& wcs, Thing2 const& thing )
   {
      wcs << "Position: x = " << thing.position.x
         << ", y = " << thing.position.y
         << ", z = " << thing.position.z
         << "\nVelocity: x = " << thing.velocity.x
         << ", y = " << thing.velocity.y
         << ", z = " << thing.velocity.z
         << "\nBoundingBox: left = " << thing.bb.left
         << " top = " << thing.bb.top
         << " right = " << thing.bb.right
         << " bottom = " << thing.bb.bottom << '\n';
      return wcs;
   }
};
Well, ok, there might be one way to have a single function.

Make each user-defined type ( structs/classes ) have a function that returns a string or wstring of it's members or whatever you want.

Code: Select all

struct Thing1
{
   std::string to_string()const
   {
      std::stringstream ss;
      ss << thing.name << " has these values "<< "a = " << thing.a << "b = " << thing.b << "c = " << thing.c << '\n';
      return ss.str();
   }
   int a, b, c;
   std::string name;
};

struct Thing2
{
   std::string to_string()const
   {
      std::stringstream ss;
      ss << "Position: x = " << thing.position.x
         << ", y = " << thing.position.y
         << ", z = " << thing.position.z
         << "\nVelocity: x = " << thing.velocity.x
         << ", y = " << thing.velocity.y
         << ", z = " << thing.velocity.z
         << "\nBoundingBox: left = " << thing.bb.left
         << " top = " << thing.bb.top
         << " right = " << thing.bb.right
         << " bottom = " << thing.bb.bottom << '\n';
      return ss.str();
   }
   Vec3f position, velocity;
   Rectf bb;
};

template<typename T>
std::wcstream& operator<<( std::wcstream& wcs, T const& value )
{
   wcs << value.to_string();
   return wcs;
}
This will end up calling your operator<<(std::wcstream&, std::string) overload.

If you don't want to overload for each type, then define a common function for each type that the single template can call and use.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

Re: operator overload : how to take care of the "rest" ?

Post by binbinhfr » May 20th, 2019, 10:41 am

Thanks for your help. I see that there is no real answer to my question. And maybe as you said, what is the need to call a function on a type that is unknown, because your function won't know anything about this unkown type's internals...

I just wanted to see if it was possible to write some kind of a default overload operator that would answer "I do not know how to handle this TYPE".

User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

Re: operator overload : how to take care of the "rest" ?

Post by cyboryxmen » May 20th, 2019, 11:09 am

Code: Select all

template<typename Type>
std::wostream& operator<<(std::wostream& ost, Type&& obj)
{
	return ost << std::string(std::forward<Type>(obj));
}
Can't get more general than that.
Zekilk

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

Re: operator overload : how to take care of the "rest" ?

Post by binbinhfr » May 20th, 2019, 12:15 pm

cyboryxmen wrote:
May 20th, 2019, 11:09 am
Can't get more general than that.
oh yes, that's almost what I did in my example that you can see in the original thread, but then everytime I try to use a wcout<< the compiler complains that it is ambiguous...
I suppose because for example it finds the original ostream<<int definition and then the template that also matches... so it cannot choose...

User avatar
cyboryxmen
Posts: 190
Joined: November 14th, 2014, 2:03 am

Re: operator overload : how to take care of the "rest" ?

Post by cyboryxmen » May 20th, 2019, 1:25 pm

Printing out an object by printing out the name of its type is ultimately useless. You're better off throwing a compiler error to signal to your users that they're doing something that doesn't make sense.

Printing out the object as a string is a good generic option to take. In fact, you don't even need the other overloads. Just use the string version.

Code: Select all

std::wostream& operator<<(std::wostream & ost, const std::string& s)
{
	return(ost << std::wstring(s.begin(), s.end()));
}

struct X
{
	X() = default;
	constexpr X(const int a) noexcept : a{a}
	{

	}

	operator std::string() const noexcept
	{
		return std::to_string(a);
	}

	int a;
};

int main()
{
	auto test = std::string("poopoo\n");

	std::wcout << "lol\n";
	std::wcout << test;
	std::wcout << X{12} << '\n';

	return EXIT_SUCCESS;
}
Zekilk

binbinhfr
Posts: 78
Joined: May 9th, 2019, 10:57 pm

Re: operator overload : how to take care of the "rest" ?

Post by binbinhfr » May 20th, 2019, 3:41 pm

cyboryxmen wrote:
May 20th, 2019, 1:25 pm
Printing out an object by printing out the name of its type is ultimately useless. You're better off throwing a compiler error to signal to your users that they're doing something that doesn't make sense.
Printing out the object as a string is a good generic option to take. In fact, you don't even need the other overloads. Just use the string version.
Yes, it was only an example.
I just wonder if there was a way to define a template overload function that would be used by default on any type where the function is not already defined...

Post Reply