Interesting GCC template issue

Started by
9 comments, last by DrPizza 19 years, 9 months ago
Okay, I'm trying to make a really, really basic debugging class. However, it's just not compiling with MinGW (GCC 3.2.3). Here's the code: Debug.h

#ifndef __DEBUG_H__
#define __DEBUG_H__

#include <iostream>

class CDebug
{
public:
	CDebug(std::ostream& ostrm) : out(ostrm) : enabled(false) {}

	void Enable(bool set) { this->enabled = set; }
	bool Enabled() { return this->enabled; }

	template<class T>
	CDebug& operator << (T item)
	{
		if(this->Enabled())
			out << item;
		return *this;
	}

private:
	std::ostream& out;
	bool enabled;
};

extern CDebug Debug;


#endif//__DEBUG_H__
Debug.cpp

#include "Debug.h"
CDebug Debug(std::clog);
main.cpp

#include <iostream>
#include "Debug.h"

int main(int argc,char* argv[])
{
	Debug.Enable(true);
	Debug << "This is a test" << std::endl;
	Debug.Enable(false);
	Debug << "This is another test" << std::endl;
	return 0;
}
This is what I get when I try to compile (using latest stable MinGW and MSYS):
$ g++ -o test.exe main.cpp -lstdc++
main.cpp: In function `int main(int, char**)':
main.cpp:30: no match for `CDebug& << <unknown type>' operator
main.cpp:32: no match for `CDebug& << <unknown type>' operator
main.cpp:34:2: warning: no newline at end of file
What exactly is wrong here?
daerid@gmail.com
Advertisement
Don't you need to put

template <class T>
class CDebug
{

};

or am I mistaken? I dunno, it's been ages since I've used C++.
That error is probably gcc's way of telling you that it doesn't know what overload for std::endl you're trying to pass to your operator<<(). Adding a specific operator<<() overloard for (std::ostream &)(*)(std::ostream &) should disambiguate things. ex:
	CDebug & operator<< (std::ostream & (*manip)(std::ostream &)) {	  if (this->Enabled())	    out << manip;	  return *this;	}
You're not really instantiating the template function with a parameter here.
In any case you want CDebug to be a stream itself so do it like this (copied from my code[inlove]):
	template <typename charT, typename Traits=std::char_traits<charT> >	class basic_logfile : public std::basic_ofstream <charT, Traits>	{		public:			explicit basic_logfile(const char* filename)			{				this->open(filename);				this->flags(std::ios_base::unitbuf);				std::time_t	t = std::time(NULL);				this->write(std::asctime(std::localtime(&t)), 24);				this->write("\n", 1);			}			~basic_logfile()			{				if (this->is_open())					this->close();			}	};    // instantiate for char type    typedef basic_logfile<char>	logfile;


now you can simply make a global out of your logfile and you will be able to output any type to it which has the << operator defined.
Anyone know a good online reference/tutorial on writing templates? Never done it myself, and now find that I have to (damn Python for spoiling me with "classes as arguments"). For example, is it possible to pass non-class arguments into template constructors?
-- Single player is masturbation.
SiCrane:

Thanks, (std::ostream &)(*)(std::ostream &) is exactly what I needed. Trying to dig that out of the definition for std::endl was turning out to be a nightmare.

And I don't want the Debug to be an ostream, I want it to wrap an ostream so that I can control what goes to it, and so I can wrap whatever ostream I want (cout,cerr,clog, any ofstream, etc).
daerid@gmail.com
Since libgdn was brought back to my attention a while ago, you might have a look at the logging system in there. It pretty much wrapped it so that you coudl use an ostream to log out, and have multiple ostreams, as well as an ostream for the console window (ie you have a windowed window and a console output window as well). There was also some overriden stuff to let you pipe one ostream in and get two ostreams out..a splitter. Also there was an HTML output manip so you coudl get colors if you wanted.

And now...I'm done.

Damn, libgdn was actually kinda decent. heh.
CDebug(std::ostream& ostrm) : out(ostrm) : enabled(false) {}


Is this even legal? I suspect not.
My stuff.Shameless promotion: FreePop: The GPL god-sim.
How else would you initialize a reference member?

I wouldn't have a reference member myself (make it a pointer), but if that's what you're going to do, that's the only way to initialize it.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
shouldn't this be

CDebug(std::ostream& ostrm) : out(ostrm) , enabled(false) {}

instead of

CDebug(std::ostream& ostrm) : out(ostrm) : enabled(false) {}

This topic is closed to new replies.

Advertisement