Sign in to follow this  
CTar

Template problem

Recommended Posts

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.

Share this post


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

Share this post


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

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