Skip to main content
gamedev.net
🔒 Locked

Template problem

Started by CTar Nov 28, 2005 at 9:15 AM 1 replies 1k views
Original Post
CTar
CTar
I have tried re-creating the streaming interface many classes in the SC++L have (like std::cout, std::ofstream etc.). I have got stuff like std::endl, std::left, std::showboolalpha etc. to work, but I still need to implement functionality for the "stuff" (what is these called? I heard the term manipulators used once, but I'm not sure if that is correct) with parameters, like std::setw. I have tried implementing the functionality, but have some problems. I have created this base interface:

#include <iostream>
#include <iomanip>

namespace Hid //Hidden/Internal stuff
{
	template<typename T, typename TParam>
	struct ManipulatorWParam
	{
		typedef void (*Func)(T& pTarget,TParam pParam);
		typedef std::pair<Func,TParam> Complete;
	};
	template<typename T>
	void setw (T& pTarget,std::streamsize pSize)
	{
		pTarget.setw (pSize);
	}
}
namespace std
{	
	template<typename T>
	typename Hid::ManipulatorWParam<T,std::streamsize>::Complete setw (std::streamsize pParam)
	{
		return Hid::ManipulatorWParam<T,std::streamsize>::Complete(Hid::setw,pParam);
	}
}
class A
{
public:	
	virtual void setw(std::streamsize pSize) = 0;

	A& operator<<(Hid::ManipulatorWParam<A,std::streamsize>::Complete pManipulator)
	{
		pManipulator.first(*this,pManipulator.second);
		return (*this);
	}
};

This might be a little complicated. Everything in Hid shouldn't be accessed from the user's code. The idea is that the user will do something like this:

(*a) << std::setw(5);
std::setw(5) will then return:

Hid::ManipulatorWParam<T,std::streamsize>::Complete(Hid::setw,5);
The << operator should then get this std::pair with a function pointer and the parameter to pass to the function pointer. The function pointer will then call A::setw with the parameter. The setw function in A is pure virtual because only classes derived from A will know what to do when setw is called, in most cases they will have an internal stream they will call. I tried creating a simple example using std::cout, like this:

class B : public A
{
public:
	void setw(std::streamsize pSize)
	{
		std::cout << std::setw(pSize);
	}
};

Now, I tried testing it like this:

int main()
{
	A* a = new B;

	(*a) << std::setw(5);

	return 0;
}

But I get the error:

e:\code\test\main.cpp(51) : error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::_Smanip<_Arg>' (or there is no acceptable conversion)
        with
        [
            _Arg=std::ios_base::fmtflags
        ]
        e:\code\test\main.cpp(31): could be 'A &A::operator <<(std::pair<_Ty1,_Ty2>)'
        with
        [
            _Ty1=void (__cdecl *)(A &,std::streamsize),
            _Ty2=std::streamsize
        ]
        while trying to match the argument list '(A, std::_Smanip<_Arg>)'
        with
        [
            _Arg=std::ios_base::fmtflags
        ]

The std::_Smanip is VC 8.0's ManipulatorWParam equivilant. It holds the function pointer and the argument value. The "A &A::operator <<(std::pair<_Ty1,_Ty2>)'" is the:

A& operator<<(Hid::ManipulatorWParam<A,std::streamsize>::Complete pManipulator)
Operator, but as you might remember Complete was just a typedef for a std::pair. So I think the compiler for some reason think the SC++L's std::setw is more appropriate. I have tried moving std::setw to another namespace, then I just get (moved to m1a namespace):

e:\code\test\main.cpp(51) : error C2783: 'Hid::ManipulatorWParam<T,std::streamsize>::Complete m1a::setw(std::streamsize)' : could not deduce template argument for 'T'
        e:\code\test\main.cpp(21) : see declaration of 'm1a::setw'
So it can't figure out the template argument, T. I tried explicitely specifiying T as A and then the code compiles fine, but I'ld like to not manually specify the type. I hope someone can help me to fix my code.
CTar
CTar
I have found a solution to my problem. Instead of having a function where the type have to be known when it is called, I have moved the template code inside the class which know which type it is. So instead of all the setw stuff at start I have created a class like this:
class setw{	std::streamsize _Param;public:	setw(std::streamsize pParam)		:		_Param( pParam )	{		}	~setw()	{		}	template<typename T>	void Execute(T& pTarget)	{		pTarget.setw( _Param );	}	};


Then the A::operator<< recieves a setw object and calls Execute.
iMalc
iMalc
Yeah that's the kind of thing I've done in similiar circumstances. It's not easy programming a lot of the stuff we take for granted is it!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.