Sign in to follow this  

Preprocessor commands in template arguments

This topic is 4856 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

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]

Share this post


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

Share this post


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

Share this post


Link to post
Share on other sites
Or learn how to do template specializations:


#include <iostream>

#define ASSERT_MAX_LEVEL 1

//general case
template < int N >
struct Assert {

Assert(bool test, const char* const msg) {
std::cerr << N << " > " << ASSERT_MAX_LEVEL << " ok\n";
}
};

//specialized case
template <>
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;

}



Share this post


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

Share this post


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

Share this post


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

Share this post


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

Share this post


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

Share this post


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

Share this post


Link to post
Share on other sites
I am having another problem with my Assert Macro. I am not sure if I should start a new thread or not, please just let me know.

Basically, I would like to make the boolean test variable also a template paramter. The boolean type that is. The reason for this is that I would like for my Assert function to return the condition so it can be used as parameter for another function.

Example:

Assert<0>(SomeObj.GetHammerPtr(), "Data Pointer was invalid")->UseHammer;


This way, I don't have to retrieve the the hammer pointer twice. Or is it just as fast to send the point to a temporary variable?

Thanks!

Dwiel

Share this post


Link to post
Share on other sites
Quote:
Original post by Tazzel3D
I am tring to write an Assert type function where the coder can set which level of errors should get through.

This might not sound very helpful but the idea of the assert is that something that should NEVER happen HAS happened. i.e. a bug HAS been found. Given that, a "level of errors" for an assert does not really make sense. All assert failures are errors.

The only reason to turn off some asserts would be because they are in your innermost loops and slow down your debug builds horribly.

Maybe the name assert isn't quite what you're meaning here as you sound like you're using asserts for things which might knowingly fail.

All the best with whatever you're trying to achieve though :-)

Share this post


Link to post
Share on other sites
Thanks for the info. The other type of things that I was planning on using assert for was for say, out of bounds checking comming in from the script that I use. Most of the time, I can simply clamp the value into the desired range instead of killing the program. It seems to require a less dramatic error than assert, but the word makes sence to me when I assert that a value should be in a given range. Now that I am thinking about it, maybe I should just pass the Assert a function, which it tries to call to fix the problem... Does this usage where I have a condition that must be true, but might have a means for recovering still seem OK, or does it sound like I should be using something else.

Thanks!

Dwiel

Share this post


Link to post
Share on other sites
Ok sure, I see.
User input checking is the kind of usage for what you are describing.

Perhaps a good name might be 'Verify', or 'ScriptVerify'?

Sorry if I sounded pedantic before! Actually I'm surprised I'm the only one so far who said what I did above.

Share this post


Link to post
Share on other sites

This topic is 4856 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.

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