Sign in to follow this  
Endar

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

Recommended Posts

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 this post


Link to post
Share on other sites
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>::type
call(input_t& input, output_t& output)
{
m_function( WRITE_ARR_ELEMENTS(N, input) );
}

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

Share this post


Link to post
Share on other sites
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> void
call(input_t& input, output_t& output)
{
m_function( WRITE_ARR_ELEMENTS(N, input) );
}

template<> void
call<false>(input_t& input, output_t& output)
{
output = m_function( WRITE_ARR_ELEMENTS(N, input) );
}


call<IsVoid>(in, out);

Share this post


Link to post
Share on other sites
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>::type
void 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 this post


Link to post
Share on other sites
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 Endar
I don't understand this bit:

typename boost::enable_if<is_void<T>, void>::type
void 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 this post


Link to post
Share on other sites
Quote:
Original post by Endar
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.


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 this post


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


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

Share this post


Link to post
Share on other sites
Quote:
Original post by Endar
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?


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 this post


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


Link to post
Share on other sites
Quote:
Original post by Endar
Okay, 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.

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