Jump to content
  • Advertisement
Sign in to follow this  
Dwiel

Preprocessor commands in template arguments

This topic is 5102 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
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 {
...
}
}

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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!