Sign in to follow this  
Yourself

function with unknow number of arguments fails to use templates

Recommended Posts

hi, language : C++ ; VS.net 2008 on Vista; I'm writing an improved (for my needs anyway) version of OutputDebugString(). you give it a string and an unknown number of arguments ,teh '%' in the string will be replace by the argument :
void DebugOutput (tstring str, ...)  
{  
	va_list args;  
	va_start(args, str);  
	tstringstream output;  

	for (int i = 0;i<(int)str.length();i++)
		if (str.at(i) == '%')
		{
			int temp = va_arg(args,int);
			output<<temp;
		}else	output<<str.at(i);

	va_end(args);  
	output<<endl;
	OutputDebugString(output.str().c_str());  
} 
as you see it works only with integers .. I want to make it a template, so I can give up any type of argument I like... so :
template <class DATATYPE>
void DebugOutput (tstring str, ...)  
{  // ...
if (str.at(i) == '%')
{
DATATYPE temp = va_arg(args,DATATYPE);
//...
that won't work :( I got a compile error saying ;
Quote:
Error 1 error C2783: 'void DebugOutput(std::wstring,...)' : could not deduce template argument for 'DATATYPE' d:\gsp xtra\vmf parser\les08-cameraskyboxapp_student\vmf_file.cpp 30
somebody knows how to fix this ?

Share this post


Link to post
Share on other sites
Quote:
Original post by Kambiz
How do you call DebugOutput? Do you specify DATATYPE explicitly like this:
*** Source Snippet Removed ***


that works :) Looks like I'm having a blond day :P
I didn't do this c'se normally the compiler fills it in..

is there also a way to work around this ?
Like if I want to passe different types :
DebugOutput<// ??> (_T("string"),5, 3.9, 9.3f );

Share this post


Link to post
Share on other sites
Quote:
Original post by Yourself
is there also a way to work around this ?
Like if I want to passe different types :
DebugOutput<// ??> (_T("string"),5, 3.9, 9.3f );

No, there's no way around this. Variadic functions are supported for backwards compatibility mostly. They're not designed to interact efficiently with modern C++ features, such as templates (this is because modern C++ uses operator overloading and chaining instead of variadic functions, for type-inference reasons).

So you'll have to provide one template argument for every one of them. For instance, you would have to define an overload of DebugOutput that takes at least three arguments, along with the appropriate template arguments:
DebugOutput<int,double,float>(/* args */);


Of course, this will require you to define a new version of DebugOutput for every different number of arguments, at which point you might as well give up on variadic functions altogether. Simply put, the point of a variadic function is to pass an arbitrary number of arguments without knowing the type of those arguments. If you need the type, then you lose any benefits of variadic functions, and might be interested by other solutions.

Share this post


Link to post
Share on other sites
I'm working on a personal tracing system and I ended up with this:


#define NCODE_TRACER_STR(_oss_,vArg) (_oss_.GetStream().str(""), _oss_.GetStream()<<vArg, _oss_.GetStream().str())




For that you need a CFormatString object that I provide, but is just a wrapper over an std::ostringstream.

The way I choose was to rely on << operator to generate string data. For example, you could do this:


CFormatString oFormatString;

NCODE_TRACER_STR(oFormatString, 2 << " HOLA " << false);
NCODE_TRACER_STR(oFormatString, 3 <<" asd " << 3.43*2.2135234232343432423234);

oFormatString.GetStream().precision(20);
NCODE_TRACER_STR(oFormatString, true << " " << 3.43*2.21123323123123123123213);
NCODE_TRACER_STR(oFormatString, std::showpos << std::scientific << 2 << " " << -23 << " " << 2.32);




All the above macros will provide a string object. If you want to have a look to the way it works you can check the library at www.ncode.byaku.net/tracer. It's open so you get the sources.

[Edited by - surfi on November 25, 2008 8:18:21 AM]

Share this post


Link to post
Share on other sites
There is also another problem, something like
DebugOutput<int>("%", 2.6);

would not cause any compile time error, although the argument has a wrong type.

Do it the c++ way using operator overloading or use boost format.

Share this post


Link to post
Share on other sites
They are going to introduce variadic templates in C++0x though, so there's a need to support variadic functions but with the benefit of type safety.

Currently, some things in boost seem to declare some things with ~20 template arguments and then probably use extensive metaprogramming magic/preprocessor to trim the unused ones (e.g boost::variant).

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