• Advertisement
Sign in to follow this  

Template problem

This topic is 4439 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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
Advertisement
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
Sign in to follow this  

  • Advertisement