Whole Tomato Software Forums
Whole Tomato Software Forums
Main Site | Profile | Register | Active Topics | Members | Search | FAQ
User name:
Password:
Save Password
Forgot your password?

 All Forums
 Visual Assist
 Technical Support
 VAX confused by macro overloading technique
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

neemo
New Member

3 Posts

Posted - Aug 10 2011 :  12:47:35 AM  Show Profile  Reply with Quote
Macro overloading seems to confuse VAX. Is there any plan to be able to support this type of macro usage, or is this simply too complex a usage of the preprocessor for VAX to ever handle?

This technique is described here, in combination with the comments: http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/

Here is a complete example that compiles in VS2008. Sorry it is so large, I threw in comments to explain the problem. It is in the main function at the end.


// -----------------------------------------------------------------------------------------------
// The ARG_COUNT macro.
//
// A variadic macro that outputs a constant number which is the number of arguments in the list.
// The complexity arises from needing to support the empty list in a cross platform way.
// NOTE: Only works for lists up to 24 arguments.
//
// i.e. 
//  int i = ARG_COUNT(1, 2, 3);
//    preprocesses to
//  int i = 3;
//
#define _EXPAND(x) x
#define _COMMA(...) ,
#define _PASTE(_0, _1) _0 ## _1
#define _PASTE3(_0, _1, _2) _0 ## _1 ## _2
#define _ARG24(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, N, ...) N
#define _HAS_COMMA(...) _EXPAND( _ARG24( __VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) )

#define _IS_EMPTY01 ,
#define _IS_EMPTY(_0, _1) _PASTE3( _IS_EMPTY, _0, _1 )
#define IS_EMPTY(...) _HAS_COMMA( _IS_EMPTY(_HAS_COMMA(__VA_ARGS__), _HAS_COMMA(_COMMA __VA_ARGS__ (~))) )

#define _ARG_COUNT1(...) 0
#define _ARG_COUNT0(...) _EXPAND( _ARG24( __VA_ARGS__, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) )
#define _ARG_COUNT(isEmpty, ...) _PASTE( _ARG_COUNT, isEmpty )(__VA_ARGS__)
#define ARG_COUNT(...) _ARG_COUNT( IS_EMPTY(__VA_ARGS__), __VA_ARGS__ )
// -----------------------------------------------------------------------------------------------


// "Macro overloading" technique
#define OVERLOAD_EXAMPLE(...) _OVERLOAD_EXAMPLE( ARG_COUNT(__VA_ARGS__), __VA_ARGS__ )
#define _OVERLOAD_EXAMPLE(argCount, ...) _EXPAND( _PASTE( _OVERLOAD_EXAMPLE, argCount )(__VA_ARGS__) )
#define _OVERLOAD_EXAMPLE0() void zeroArgFunc() {}
#define _OVERLOAD_EXAMPLE1(t1) void oneArgFunc(t1 arg1) {}
#define _OVERLOAD_EXAMPLE2(t1, t2) void twoArgFunc(t1 arg1, t2 arg2) {}
#define _OVERLOAD_EXAMPLE3(t1, t2, t3) void threeArgFunc(t1 arg1, t2 arg2, t3 arg3) {}
// .
// .
// and (potentially) so on..

class TestClass
{
public:

	OVERLOAD_EXAMPLE(); // Declare a zero argument function accepting no params
	OVERLOAD_EXAMPLE(int); // Declare a one argument function accepting an int
	OVERLOAD_EXAMPLE(float, int); // Declare a two argument function accepting a float and an int
	OVERLOAD_EXAMPLE(float, int, short); // .. you get the idea
};

int main()
{
	TestClass t;

	// This compiles, but VAX is unable to display any information about these functions or syntax highlight them :(
	t.zeroArgFunc();
	t.oneArgFunc(1);
	t.twoArgFunc(1.0f, 1);
	t.threeArgFunc(1.0f, 1, 1);

	return 0;
}

Edited by - neemo on Aug 10 2011 12:51:05 AM

accord
Whole Tomato Software

United Kingdom
3287 Posts

Posted - Aug 10 2011 :  06:58:24 AM  Show Profile  Reply with Quote
You can make VA create the functions for you but you will need to pull a tick on VA for this. If you pre-define the macro for VA, with all version of the function included, you will get better result:

#define OVERLOAD_EXAMPLE \    void zeroArgFunc() {}\    void oneArgFunc(t1 arg1) {}\    void twoArgFunc(t1 arg1, t2 arg2) {}\    void threeArgFunc(t1 arg1, t2 arg2, t3 arg3) {}

Just put the result into this file:
http://docs.wholetomato.com?W302

It won't be seen by the compiler and when VA will parse your actual code, the macro won't get overridden.

Anyway, where _PASTE comes from?
Go to Top of Page

neemo
New Member

3 Posts

Posted - Aug 11 2011 :  5:52:15 PM  Show Profile  Reply with Quote
_PASTE is the 3rd macro from the top of the example. The main idea of this whole technique is getting the ARG_COUNT macro to work (which is unfortunately a little bit complicated).

Once you do though, you can create "overloaded" version of any macro by appending its variable argument count to it. I think for this particular contrived example, your solution might work for the fixed function names. But, in more real life examples, I don't think this solution will work, because the function names and signatures are not fixed or known ahead of time.

Here is an example: I want to declare an RPC method of varying arguments with a single macro, and similarly be able to implement it with a single macro. The idea is that a bunch of other stubs and code may need to be implemented to support the rpc that we want to hide in a macro. In the example I've skipped these details with comments. But hopefully this will give an idea of how powerful this technique is. This code compiles in visual studio 2008:

EDIT: Correction, NOW this compiles in visual studio 2008..


// Assume the ARG_COUNT macro exists / works. It is in the first post. 

// Declare class RPCs
#define DECLARE_NET_FUNC(retType, name, ...) _DECLARE_NET_FUNC( ARG_COUNT(__VA_ARGS__), retType, name, __VA_ARGS__ )
#define _DECLARE_NET_FUNC(argCount, retType, name, ...) _EXPAND( _PASTE( _DECLARE_NET_FUNC, argCount )(retType, name, __VA_ARGS__) )
#define _DECLARE_NET_FUNC0(retType, name, null ) \    retType name() { /* some special code that fires you off as an rpc */ return name##_impl(); } \    retType name##_impl()

#define _DECLARE_NET_FUNC2(retType, name, t1, p1) \    retType name(t1 p1) { /* some special code that fires you off as an rpc */ return name##_impl(p1); } \    retType name##_impl(t1 p1)

#define _DECLARE_NET_FUNC4(retType, name, t1, p1, t2, p2) \    retType name(t1 p1, t2 p2) { /* some special code that fires you off as an rpc */ return name##_impl(p1, p2); } \    retType name##_impl(t1 p1, t2 p2)

// Implement class RPCs
#define IMPLEMENT_NET_FUNC(retType, class, name, ...) _IMPLEMENT_NET_FUNC( ARG_COUNT(__VA_ARGS__), retType, class, name, __VA_ARGS__ )
#define _IMPLEMENT_NET_FUNC(argCount, retType, class, name, ...) _EXPAND( _PASTE( _IMPLEMENT_NET_FUNC, argCount )(retType, class, name, __VA_ARGS__) )
#define _IMPLEMENT_NET_FUNC0(retType, class, name, null) retType class::name##_impl()
#define _IMPLEMENT_NET_FUNC2(retType, class, name, t1, p1) retType class::name##_impl(t1 p1)
#define _IMPLEMENT_NET_FUNC4(retType, class, name, t1, p1, t2, p2) retType class::name##_impl(t1 p1, t2 p2)


// Now I can very cleanly declare RPCs of any signature automatically with NO overhead!
class MyRPCClass
{
    DECLARE_NET_FUNC(void, netSignalOne);
    DECLARE_NET_FUNC(void, netSignalTwo, int, errCode);
    DECLARE_NET_FUNC(void, netSignalThree, int, errCode, const char*, errMessage);
};

IMPLEMENT_NET_FUNC(void, MyRPCClass, netSignalOne)
{
// code for signal one
}

IMPLEMENT_NET_FUNC(void, MyRPCClass, netSignalTwo, int, errCode)
{
// code for signal two
}

IMPLEMENT_NET_FUNC(void, MyRPCClass, netSignalThree, int, errCode, const char*, errMessage)
{
// code for signal three
}



It would be more than awesome if VAX could somehow unravel this "macro mess"

Edited by - neemo on Aug 11 2011 11:50:01 PM
Go to Top of Page

neemo
New Member

3 Posts

Posted - Aug 12 2011 :  12:22:00 AM  Show Profile  Reply with Quote
Also wanted to point out, I tried what is here: http://docs.wholetomato.com?W363

And the functions declared through the macros are still not "visible" to VAX
Go to Top of Page

accord
Whole Tomato Software

United Kingdom
3287 Posts

Posted - Aug 12 2011 :  11:43:27 AM  Show Profile  Reply with Quote
You can try turning on the following option to see if it makes a difference:

VAssistX -> Visual Assist X Options... -> Listboxes -> Get content from default intellisense

It will get listbox content from intellisense, thus it will work much better with VS2010 but you may have some success using older VS2008 if you only use that version.

Your examples are pretty complex and it would need a compiler like precision of code parsing. VA is optimized for speed thus may not understand everything that the compiler do but do its work multiple times faster even on very large code bases. Hope the listbox option will help.
Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
© 2023 Whole Tomato Software, LLC Go To Top Of Page
Snitz Forums 2000