/* Use boost pre-processor stuff to generate the elements of an array, because we'll only know
at compile time how many params are needed. This is because I'm using boost::function which uses
templates and it's easier to work like this than just put in 30 template parameters, most of which
will end up as nothing.
When the macro "WRITE_ARR_ELEMENTS" is called, depending on the input it will print
array elements. Eg. an input of (4,vertex) will expand to
"vertex[0] , vertex[1] , vertex[2] , vertex[3]" during the preprocessor stage.
*/
#define WRITE_ELEMENT(z, n, arr) BOOST_PP_COMMA_IF(n) BOOST_PP_CAT(arr[, BOOST_PP_CAT(n, ]))
#define WRITE_ARR_ELEMENTS(n, input) BOOST_PP_REPEAT(n, WRITE_ELEMENT, input )
/**
* Concrete class for the function wrapper.
* NOTE:: the "BOOST_PP_ENUM_PARAMS(N, T)" preprocessor macro will insert T0, T1, T2, etc, up to the
* limit 'N', using the preprocessor ## to stick stuff together.
*/
template < BOOST_PP_ENUM_PARAMS(N, class T) >
class CFunctionWrapper : public IFunctionWrapper
{
private:
/** Boost function wrapper
* Note: to use the <T0,T1,T2,T3> we need to use boost::function2.
* If we want to use the < int (float i, char c) > form, we need boost::function
*/
boost::function2< BOOST_PP_ENUM_PARAMS(N, T) > m_function;
public:
/**
* Call the function.
* \param s A reference to a std::string object to store in any error messages
* caused when calling the function
* \param input A const reference to a util::array<boost::variant> object to store the input arguments.
* \param output A reference to a variant that will store the return value.
* \return 'true' if the call was successful, else 'false'
*/
bool call( std::string& s,
const echo::util::array< console_variant_type >& input,
console_variant_type& output )
{
// not enough function arguments
if( input.getSize() != N ){
s = "Error: not enough function arguments."; // assign error message
return false; // return error
}
// call the function
output = m_function( WRITE_ARR_ELEMENTS(N, input) );
return true;
}
};
🔒 Locked
Template parameter problem (C++)
Advertisement
Original Post
Okay, I'm having a little bit of trouble with template parameters. Take a little looksee, focusing mostly on the CFuntionWrapper template params My trouble is that I can't figure out how I'm going to be able to pass in the number 'N'. I'm not looking to do that at runtime, I'm sure that it needs to be done at compile time, and that's fine, no problem there. I just can't figure out how I'm going to be able to do it.
Given you're using it in with BOOST_PP macros, the only way you can "pass" it is to #define it. Defining it before you include the header that contains the template definition, then undefining it is probably the best solution. If you want to generate the template several times with different N, there are tricks in BOOST_PP to do that.
But it all has to be done with constants, right? For every template class that has a different number of template params, I'll have to have a preprocessor statement, won't I?
Hmmmm. It might be time to think about doing this another way, without all the boost preprocessor stuff.
Hmmmm. It might be time to think about doing this another way, without all the boost preprocessor stuff.
Quote:
Original post by Endar
But it all has to be done with constants, right? For every template class that has a different number of template params, I'll have to have a preprocessor statement, won't I?
You can use BOOST_PP_REPEAT or BOOST_PP_ITERATE to have it done automatically.
With BOOST_PP_REPEAT, you generate your class definition as a macro, which would take N as a (macro) parameter, and BOOST_PP_FOR will call the macro a number of times, with the appropriate values of N.
With BOOST_PP_ITERATE, you would put your class in a header file (without include guards) and BOOST_PP_ITERATE would include that header a number of times, defining N (or other iteration variable) accordingly prior to inclusion.
With BOOST_PP_REPEAT
With BOOST_PP_ITERATE
Or, the same, as one self-including file:
Of course, if you don't like heavy preprocessor magic ...
#include <boost/preprocessor/repetition/repeat.hpp>#define DEFINE_CFunctionWrapper(Z, N, TEXT) \ template < BOOST_PP_ENUM_PARAMS(N, class T) > \ class CFunctionWrapper : public IFunctionWrapper \ { \ // stuff \ };// Generate CFunctionWrapper for N = 0 to 9BOOST_PP_REPEAT(10, DEFINE_CFunctionWrapper, dummy)With BOOST_PP_ITERATE
CFunctionWrapper.h#include <boost/preprocessor/iteration/iterate.hpp>#define BOOST_PP_FILENAME_1 "CFunctionWrapper.inc"#define BOOST_PP_ITERATION_LIMITS (0, 9)#include BOOST_PP_ITERATE()CFunctionWrapper.inc#define N BOOST_PP_ITERATION()template < BOOST_PP_ENUM_PARAMS(N, class T) >class CFunctionWrapper : public IFunctionWrapper{ // stuff};#undef NOr, the same, as one self-including file:
CFunctionWrapper.h#if !BOOST_PP_IS_ITERATING #ifndef INCLUDE_CFUNCTIONWRAPPER_H #define INCLUDE_CFUNCTIONWRAPPER_H #include <boost/preprocessor/iteration/iterate.hpp> #define BOOST_PP_FILENAME_1 "CFunctionWrapper.h" #define BOOST_PP_ITERATION_LIMITS (0, 9) #include BOOST_PP_ITERATE() #endif#else #define N BOOST_PP_ITERATION() template < BOOST_PP_ENUM_PARAMS(N, class T) > class CFunctionWrapper : public IFunctionWrapper { // stuff }; #undef N#endifOf course, if you don't like heavy preprocessor magic ...
In fact, you probably want BOOST_PP_LOCAL_ITERATE() rather than BOOST_PP_REPEAT.
It might be faster than using file iteration with BOOST_PP_ITERATE.
#include <boost/preprocessor/iteration/local.hpp>#define BOOST_PP_LOCAL_MACRO(N) \ template < BOOST_PP_ENUM_PARAMS(N, class T) > \ class CFunctionWrapper : public IFunctionWrapper \ { \ // stuff \ };// Generate CFunctionWrapper for N = 0 to 9#define BOOST_PP_LOCAL_LIMITS (0, 9)#include BOOST_PP_LOCAL_ITERATE()It might be faster than using file iteration with BOOST_PP_ITERATE.
Hmmmm.
Note: please don't ask or complain about the formatting. I've fixed it about 4 times and every single time GD makes it exacly as you see it. I've given up trying to fix it.
This is what I'm using, but it's only repeating the first line, the template parameter line.
Here's the relevant excerpt of the source after the compiler's (VC++ 2005 express) preprocessing stage:
Note: in the first bit, I don't know why, but it gets rid of the '\' where there is a blank line. Probably because there are no tokens for parsing between the previous '\' and the next token.
So, I'm not really sure where to go from here.
I'm not sure how to even debug something like this. If I look at the boost preprocessor source I can't understand half of it. I just don't have much experience at all except with simple preprocessor stuff.
Edit: code formatting fixed
[Edited by - Endar on April 14, 2006 2:22:42 AM]
Note: please don't ask or complain about the formatting. I've fixed it about 4 times and every single time GD makes it exacly as you see it. I've given up trying to fix it.
#define BOOST_PP_LOCAL_MACRO(n) \ template < BOOST_PP_ENUM_PARAMS(n, class T) > \ class CFunctionWrapper \ {public: \ int i; \ }; \ /**/This is what I'm using, but it's only repeating the first line, the template parameter line.
Here's the relevant excerpt of the source after the compiler's (VC++ 2005 express) preprocessing stage:
Note: in the first bit, I don't know why, but it gets rid of the '\' where there is a blank line. Probably because there are no tokens for parsing between the previous '\' and the next token.
class CFunctionWrapper \ { \ public: \ int i; \ }; \ #line 1 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 15 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 17 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 28 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 29 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 33 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < > \ #line 36 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 > \ #line 39 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 > \ #line 42 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 > \ #line 45 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 , class T3 > \ #line 48 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 , class T3 , class T4 > \ #line 51 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 , class T3 , class T4 , class T5 > \ #line 54 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 , class T3 , class T4 , class T5 , class T6 > \ #line 57 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 , class T3 , class T4 , class T5 , class T6 , class T7 > \ #line 60 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp" template < class T0 , class T1 , class T2 , class T3 , class T4 , class T5 , class T6 , class T7 , class T8 > \ #line 63 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 66 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"#line 69 "c:\\program files\\boost library\\boost\\preprocessor\\iteration\\detail\\local.hpp"So, I'm not really sure where to go from here.
I'm not sure how to even debug something like this. If I look at the boost preprocessor source I can't understand half of it. I just don't have much experience at all except with simple preprocessor stuff.
Edit: code formatting fixed
[Edited by - Endar on April 14, 2006 2:22:42 AM]
In the code I posted, I added a space after the trailing backslash because, as you found out yourself, if you don't, the forum software will run the lines together.
Make sure the backslash is actually the last character on the line in your code, but add a space when posting here. [smile]
Make sure the backslash is actually the last character on the line in your code, but add a space when posting here. [smile]
This should be the last thing [grin]
Okay, I've got it working, but I've found that I had to put class BOOST_PP_CAT(CFunctionWrapper, n) for the class name, so with 1 template param it's "CFunctionWrapper1", then "CFunctionWrapper2", etc, etc.
This is because you can't have overloaded class templates, right? As soon as you declare it with whatever number of template params, it's set in stone, right?
Edit:: Am I also right in thinking that you can't have comments in a preprocessor macro?
Okay, I've got it working, but I've found that I had to put class BOOST_PP_CAT(CFunctionWrapper, n) for the class name, so with 1 template param it's "CFunctionWrapper1", then "CFunctionWrapper2", etc, etc.
This is because you can't have overloaded class templates, right? As soon as you declare it with whatever number of template params, it's set in stone, right?
Edit:: Am I also right in thinking that you can't have comments in a preprocessor macro?
Quote:
Original post by Endar
This is because you can't have overloaded class templates, right? As soon as you declare it with whatever number of template params, it's set in stone, right?
Correct. Works just fine for function templates though.
You can generate a front-end using default template parameters. It will require having a preprocessor constant indicating the maximum number of template parameters you can handle, so that it can be changed easily.
class IFoo{protected: // A unique type used as a placeholder struct undef;};// Automatically generated by what you currently havetemplate<class T0> class Foo0 : public IFoo { /**/ };template<class T0, class T1> class Foo1 : public IFoo { /**/ };template<class T0, class T1, class T2> class Foo2 : public IFoo { /**/ };template<class T0, class T1, class T2, class T3> class Foo3 : public IFoo { /**/ };// The primary template is a special case // without arguments after the class name and// with default parameters in the parameter list.template<class T0, class T1=IFoo::undef, class T2=IFoo::undef, class T3=IFoo::undef>class Foo : public Foo3<T0,T1,T2,T3> { /**/ };// The partial specializations can be generated, up to N-1.template<class T0, class T1, class T2>class Foo<T0,T1,T2,IFoo::undef> : public Foo2<T0,T1,T2> { /**/ };template<class T0, class T1>class Foo<T0,T1,IFoo::undef,IFoo::undef> : public Foo1<T0,T1> { /**/ };template<class T0>class Foo<T0,IFoo::undef,IFoo::undef,IFoo::undef> : public Foo0<T0> { /**/ };int main(){ Foo<int> a1; Foo<int,int> a2; Foo<int,int,int> a3; Foo<int,int,int,int> a4;}Note that since you're wrapping functions, you may want to have the result type separate from the Tn parameters:
template
[Edited by - Fruny on April 14, 2006 5:13:55 AM]
Oh, and you may want to have a look at this thread.
Fruny, you have been so helpful to me, so I rated you up.
It didn't do much, I think you got a whole 2 points. [grin]
It's compiling properly the the preprocessing stage output looks good, so I'm going to go to bed before I break it again.
Thanks for the links, that's going to be the first thing I look at when I turn the computer on tomorrow.
It didn't do much, I think you got a whole 2 points. [grin]
It's compiling properly the the preprocessing stage output looks good, so I'm going to go to bed before I break it again.
Thanks for the links, that's going to be the first thing I look at when I turn the computer on tomorrow.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement