Preprocessor commands in template arguments

Started by
12 comments, last by iMalc 19 years, 8 months ago
Hello, I was wondering if it is legal to use a preprocessor command on a template argument. I am tring to write an Assert type function where the coder can set which level of errors should get through. Example:

#define ASSERT_MAX_LEVEL 1

float* val;
Assert<0>(val, "val is a null pointer");
if(val < 0)
{
    val = 0;
    Assert(5, "val was < 0, but has been changed to 0);
}




Here is how I have attempted to solve the problem:

#include <boost/preprocessor/comparison/greater.hpp>

#define ASSERT_MIN_LEVEL 2

template<int lvl> void Assert(bool test, char* msg)
//#if BOOST_PP_LESS(lvl, ASSERT_MAX_LEVEL)
#if lvl <= ASSERT_MAX_LEVEL
	{
		cout << "assertion" << endl;
	}
#else
	{
		cout << lvl << " > " << ASSERT_MAX_LEVEL << " ok" << endl;
	}
#endif




For some reasonno matter what I set MAX_LEVEL to, the else code is called. Well, it looks like ive figured out part of the problem... it looks like the template is only generated once. The value I use for lvl in the last use of Assert is what seems to be used for every Assert. I am using VC++6.0 for compilation. Any ideas on how I can do what I am trying to do? The main reason I am using templates is because I am hopefully going to incorperate this function into a logging class. [EDIT] I just popped in a '#define ASSERT_LVL lvl' right after the template line and put it in the cout. This outputs the correct value, which kills me previous theory which was that the preprocessor didnt know what the value for lvl was. Althouh, it still only 'sees' a single value for lvl (the last one) Thanks Dwiel [Edited by - Tazzel3D on August 25, 2004 5:47:11 PM]
Advertisement
Nope. The preprocessor is a lot stupider than templates are. Where a template function is evaluated every time it is provided template arguments, the preprocessor will only run every time the file is compiled. (or #included)

In this case, you can just use an if statement. The template argument is known at compile-time, so un-callable code will be clipped out automatically:

template <bool cond> void Assert(bool test, char* msg) {    if (cond) {         ...     } else {        ...    }}
"There is only one everything"
Thanks a bunch. I didnt realize that the compiler would do simple tests like that, which are known at compile time. I guess I should have known. Compilers arent very stupid.

Thanks!

Dwiel
Or learn how to do template specializations:

#include <iostream>#define ASSERT_MAX_LEVEL 1//general casetemplate < int N >struct Assert {   Assert(bool test, const char* const msg) {      std::cerr << N << " > " << ASSERT_MAX_LEVEL << " ok\n";   }};//specialized casetemplate <>struct Assert< 0 > {   //different implementation goes here   Assert(bool test, const char* const msg) {      std::cerr << "assertion\n";   }};int main() {   Assert< 4 >(true, "LALA");   Assert< 0 >(true, "LALA");   return 0;}


Actually, that didnt work. It looks like the template is still being 'used' only once. Example:

#include <iostream>using namespace std;template<bool cond> void _ASSERT(bool test, char* msg){	if(cond)	{		if(!test)			cout << "ASSEERT: " << msg << endl;	}}int main(void){	_ASSERT<true>(0, "error 5");	_ASSERT<false>(0, "error 4");	return 0;}


That displays nothing. If I reverse the order of the templates, both are displayed. Any ideas?

[EDIT] snk_kid: The whole point is so that when I go to compile, I can change the max level define and alter what is actually compiled. I would like to have more control than just turning Assert<0> on and off. I could do that by making a Warning macro, with a corresponding USE_WARNINGS define. I would like to be able to set what warning level should be the maximum for inclusion. If there is to do this with template specialization, I'm all for it. The only thing I can think of is to use Boost::Preprocessor generate specialized Asserts for all integers from 0 to ASSERT_MAX_LEVEL, but that seems a bit convoluted. I guess actually, I'll start working doing that until someone comes up with a better idea.

Thanks!

Dwiel
Quote:Original post by Tazzel3D
Actually, that didnt work. It looks like the template is still being 'used' only once.


which version are you refering to? did you check my example? the key here i think is recursive template instantiation.
Quote:Original post by Tazzel3D
snk_kid: The whole point is so that when I go to compile, I can change the max level define and alter what is actually compiled.


You can still do that, the above was just a simple example of template specialization.

Quote:Original post by Tazzel3D
I would like to have more control than just turning Assert<0> on and off. I could do that by making a Warning macro, with a corresponding USE_WARNINGS define. I would like to be able to set what warning level should be the maximum for inclusion. If there is to do this with template specialization, I'm all for it.


You lost me here, can give an example of what your talking about.
I actually just made it so your template specialization works the way I want. Thanks a bunch!

I simply used a macro to generate specializations for all integers between 0 and ASSERT_MAX_DEBUG_LEVEL, inclusive. For those who are interested:

#include <boost/preprocessor/arithmetic/inc.hpp>#include <boost/preprocessor/comparison/not_equal.hpp>#include <boost/preprocessor/repetition/for.hpp>#include <boost/preprocessor/tuple/elem.hpp>#define PRED(r, state)    BOOST_PP_NOT_EQUAL(       BOOST_PP_TUPLE_ELEM(2, 0, state),       BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(2, 1, state))    )    /**/#define OP(r, state)    (       BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(2, 0, state)),       BOOST_PP_TUPLE_ELEM(2, 1, state)    )    /**///specialized cases#define MACRO(r, state) template <> struct Assert< BOOST_PP_TUPLE_ELEM(2, 0, state) > { Assert(bool test, const char* const msg) { std::cerr << "assertion\n"; } };BOOST_PP_FOR((0, ASSERT_MAX_DEBUG_LEVEL), PRED, OP, MACRO)


basically, what I wanted was to be able to define ASSERT_MAX_DEBUG_LEVEL as some intereger and then all asserts with a level above that would be removed. So if I want to remove all asserts, I make the max -1. If I want to see them all I set it to 100. If I just want to see the major ones, I set it to 3, etc.

Thanks again!

Dwiel
i'm sure boost have compile-time assertions, anyways if your interested maybe you can combine that with the run-time assertion functions i posted earlier on today here its at the bottom.
I actually have my own Assertion code, but what I saw at your post is very interesting. I might go ahead and base my new one on that example. Thanks a lot!

Dwiel

This topic is closed to new replies.

Advertisement