# Unity more preprocessor help (C++) [updated]

## Recommended Posts

Endar    668
Okay, I'm back asking more questions on this topic, so, if you're new, reading through this whole thing might help if you ever need to perform some preprocessor magic. :D This is the start of the current batch of posts.
Okay, I'm back with more preprocessor questions, this time hopefully it will be quick and easy. I'm using boost and a bunch of boost preprocessor macros to create different definitions of a template class. My current problem is that at one point I have this code snippet:
/* this evaluates to true iff 'R' is 'void' */
/* http://www.boost.org/doc/html/boost_typetraits.html */
if( m_isVoid.value )
/* if the return is void, don't set the return value */
m_function( WRITE_ARR_ELEMENTS(N, input) );
/* Call the function and get the return value */
else
output = m_function( WRITE_ARR_ELEMENTS(N, input) );


Where m_function is a boost::functionN object, and output is a boost::variant which contains pretty much every primitive type, a pointer to every primitive type and also contains the same for std::string. The macro will expand like so: WRITE_ARR_ELEMENTS(2, array) will expand to "boost::get<T0>(array[0]) , boost::get<T1>(array[1])" So, my current problem is that the assignment causes the compiler to have a fit when 'void' is the return value because void isn't in the boost::variant template list for obvious reasons. So, I'm looking for a way to identify at preprocessor time whether a template parameter is 'void' or not, which I'm fairly sure is impossible as types don't matter until the code is actually compiled. [Edited by - Endar on May 2, 2006 7:29:41 PM]

##### Share on other sites
Sharlin    864
I don't think you need to check for void at preprocessor time; compile time works just fine (note: currently you do the check at *run* time). Write two templated overloads for the function, and use boost::enable_if to select the correct overload. Something like this:

typename boost::enable_if<IsVoid, void>::typecall(input_t& input, output_t& output){  m_function( WRITE_ARR_ELEMENTS(N, input) );}typename boost::disable_if<IsVoid, void>::typecall(input_t& input, output_t& output){  output = m_function( WRITE_ARR_ELEMENTS(N, input) );}

##### Share on other sites
Endar    668
I've been looking at that, and I don't understand how it works.

##### Share on other sites
Fruny    1658
It works on the SFINAE principle (substitution failure is not an error), which means that if parameter substitution generates a nonsensical template then that template is just ignored during overload resolution instead of generating an error.

In practice, if IsVoid is false, the compiler will not see the first function, and if false, it will not see the second.

Of course, in the present case, you could just write:

template<bool b> voidcall(input_t& input, output_t& output){  m_function( WRITE_ARR_ELEMENTS(N, input) );}template<> voidcall<false>(input_t& input, output_t& output){  output = m_function( WRITE_ARR_ELEMENTS(N, input) );}call<IsVoid>(in, out);

##### Share on other sites
Endar    668
Okay, well, help. This is a test class so I can get the concept working before plugging it into my real code (which incidently is also test code, so I can get that working, and so on).

template <class T>class A{public:	/* is_void only inherits from 'false_type' iff the template param */	/* is not 'void' */	template <class A>	struct is_void	:	public boost::false_type{};	/* is_void only inherits from 'true_type' iff the template param */	/* is 'void' */	template <>	struct is_void<void>	:	public boost::true_type{};	typename boost::enable_if<is_void<T>, void>::type	void func( )	{		printf("\n Enabled!! \n");	}	typename boost::disable_if<is_void<T>, void>::type	void func( )	{		printf("\n Disabled!! \n");	}};// class A

I don't understand this bit:
typename boost::enable_if<is_void<T>, void>::typevoid func( )

I don't understand how this is proper syntax. How does the "typename boost::stuff" supposed to be valid? I mean, it's obviously not a return type. The function doesn't look like a template function.

I'm kind of in the dark.

Fruny:: I would go with your code except for the fact that when I put it into it's final destination in my project, I'll be calling the 'call' function from outside the class, and I don't want to have to remember to always call the 'call' function with a template param like that.

##### Share on other sites
Sharlin    864
First off, as I suddenly realised, enable_if doesn't work very well in this case, because SFINAE is only invoked on function templates, not on any old overload. So, my example was misleading. Anyway, in this particular case, Fruny's advice should probably be followed. You don't need to explicitly write the template parameter everywhere, just write a trivial wrapper:

void call(input_t& input, output_t& output){  call_helper<is_void::value>(input, output);}private: template<bool b> void call_helper(input_t& input, output_t& output){  m_function( WRITE_ARR_ELEMENTS(N, input) );}template<> void call_helper<false>(input_t& input, output_t& output){  output = m_function( WRITE_ARR_ELEMENTS(N, input) );}call(in, out);

But, for reference:

Quote:
 Original post by EndarI don't understand this bit:typename boost::enable_if, void>::typevoid func( )

You have one void too many: the typename .. ::type part *is* the return value - a typedef for the second template parameter (which defaults to void). Basically it is just a clever trick to explicitly invoke SFINAE; the actual implementation of enable_if is very simple (straight from the docs:
template <bool B, class T = void>struct enable_if_c {  typedef T type;};template <class T>struct enable_if_c<false, T> {};template <class Cond, class T = void>struct enable_if : public enable_if_c<Cond::value, T> {};

Thus, if you have this:

template<typename T>
typename boost::enable_if<is_void<T> >::type func( );

then, if the condition evaluates to true, the nested typedef type exists and the declaration is well-formed and will thus be considered (and selected) in overload resolution. If not, there's no typedef and the declaration invalid - but SFINAE says that this will not result in error, the function will just be ignored.

##### Share on other sites
Fruny    1658
Quote:
 Original post by EndarFruny:: I would go with your code except for the fact that when I put it into it's final destination in my project, I'll be calling the 'call' function from outside the class, and I don't want to have to remember to always call the 'call' function with a template param like that.

You can probably solve that with another layer of indirection (i.e. another function call). The function calls will probably be optimized away (think 'inline').

##### Share on other sites
Endar    668
Okay, I think it's done.

I'll just post my test code here for anyone else who happens along this thread.

template <class T>class A{public:	/* is_void only inherits from 'false_type' iff the template param */	/* is not 'void' */	template <class A>	struct is_void	:	public boost::false_type{};	/* is_void only inherits from 'true_type' iff the template param */	/* is 'void' */	template <>	struct is_void<void>	:	public boost::true_type{};	void func()	{		func_helper< is_void<T>::value >();	}	template <bool b>	void func_helper( )	{		printf("\n Enabled!! \n");	}	template <>	void func_helper<false>( )	{		printf("\n Disabled!! \n");	}};// class A

Thanks guys, I should be okay now, but who knows? [smile]

##### Share on other sites
Endar    668
Okay, well, actually as long as I'm here, I might as well ask my last question, else I'll have to explain the whole thing again in another thread.

The non-member functions seem to work pretty well, I'm just working on getting member functions to work.

If you don't know how boost::function works, if you're calling a member function you need a pointer to the object as the first function argument like so:

struct A{// stuff here};int main(){	boost::function< void (A*) > f;}

Currently I have my constuctor made up with boost preprocessor macros to expand like this:
CFunctionWrapper_1 ( R (*f)(  T0 ) )

Where R is the template param for the return value and T0 is the first function argument. This is obviously for a function with only 1 argument.

My main problem is that I don't want to have to add another type to the template parameter of the boost::variant type that I'm using every time I want to use a new object or another function.

Anyone have a creative idea? Or would the best idea be to just forget member functions and stick with non-member functions?

Endar    668
beep

.... Uh, bump.

##### Share on other sites
Fruny    1658
Quote:
 Original post by EndarMy main problem is that I don't want to have to add another type to the template parameter of the boost::variant type that I'm using every time I want to use a new object or another function.Anyone have a creative idea? Or would the best idea be to just forget member functions and stick with non-member functions?

I don't have a perfect solution for you, sorry. boost::any might help, so might using a common base class. Or boost::bind, to associate the function with a specific object.

##### Share on other sites
Endar    668
Okay, I'm back. Again.

I'm working on associating a boost::function object with a specific member function for a specific object.

I'm still using this thread, because every post before this one is related.

I believe a solution that will work is to create another class. So, where I am using boost preprocessor magic to create 10 classes each with a different number of template params, I'm doing the same thing except I'm calling this one "CObjectFunctionWrapper."

From what I've seen in the boost documentation, the only think I have to change is the constructor, so I've added another template parameter to denote the object type, and I'm attempting to use std::bind1st with std::mem_fun.

This is what I have so far:
/* Constructor */BOOST_PP_CAT(CObjectFunctionWrapper_ , N) ( O* object, R (__thiscall *O::f)( BOOST_PP_ENUM_PARAMS(N, T) ) ){	m_function = std::bind1st( std::mem_fun(f), object );}

I'm a little stuck specifying the function pointer param.

I also tried "__thiscall O::*f" instead of "__thiscall *O::f", and then I get no error specifically for that bit, but I get errors with std::mem_fun, template problems, which make me think that I haven't actually solved the problem.

I'm working on it, but anything you could throw my way would be helpful.

##### Share on other sites
Fruny    1658
Quote:
 Original post by EndarOkay, I'm back. Again.I'm working on associating a boost::function object with a specific member function for a specific object.

Uhhhhhhh.

#include <boost/function.hpp>#include <boost/bind.hpp>struct Foo{   int bar(double) { /* ... */ }};Foo obj;boost::function<int (double)> fn;// Using a pointer to avoid copying obj into fn.// Could use boost::ref instead.fn = boost::bind(&Foo::bar, &obj, _1);int i = fn(3.14159);

Note: std::mem_fun, std::bind1st and the like only work with unary and binary functions. That's why there's boost::bind and boost::mem_fn.

## Create an account

Register a new account

• ### Similar Content

• By notrodta
Hi, I'm currently developing a game with a friend on Unity. We have the majority of our first prototype ready. We are searching for a 2d artist and a musician. If you are interested, feel free to contact us. We also have a demo of the game we can send you for those of you who are interested.
https://forums.tigsource.com/index.php?topic=61923.msg1347252#msg1347252
Below is a short youtube video containing few clips of our game:

• By Yotingo
This is how Odd Oliver see eclipses.

@gygestudios
gyge.co
@yotingo

• You - the chief doctor of the hospital. Working late into the evening, did not notice the majority of hospital workers went home ... But where you disappeared the night shift is also not known. Hastily taking important documents, go home, but something went wrong as usual ... Can you get out of the hospital alive?

We are looking for every position. From Game designer, to marketer, to programmer, to 3D modeler. Any further questions can be discussed through discord
DISCORD: Gator#5635

• Wind Of Fear is a game where we have to kill different kinds of waves of monsters packing weapons. The main goal is to survive the waves and pump up your own weapons. There is a store where you will buy new weapons, scattered crystals that restore your life are also on the map!

Controls:
WASD - Walking
Shift - Running
Mouse1 - Attack
Space - Jump
ScrolDown - weapon change
T - Deceleration of time