Fix wxCALL_FOR_EACH() to work with more than 2 arguments with MSVC.

Due to a bug in MSVC handling of __VA_ARGS__ (see
https://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement)
wxCALL_FOR_EACH() didn't work correctly as long as more than two arguments
were used with it.

Work around the bug by protecting __VA_ARGS__ from being incorrectly passed as
a single token to the macro being called on every step: this was already done
for wxCALL_FOR_EACH itself with wxCALL_FOR_EACH_, but we need to do it for all
the helper macros too.

Also add a test checking that this does, actually, work.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77689 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2014-09-14 00:59:53 +00:00
parent da5edc0fc1
commit c2e18d75e5
2 changed files with 34 additions and 7 deletions

View File

@ -164,14 +164,23 @@
#define wxCALL_FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define wxCALL_FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
#define wxCALL_FOR_EACH_1_(args) wxCALL_FOR_EACH_1 args
#define wxCALL_FOR_EACH_2_(args) wxCALL_FOR_EACH_2 args
#define wxCALL_FOR_EACH_3_(args) wxCALL_FOR_EACH_3 args
#define wxCALL_FOR_EACH_4_(args) wxCALL_FOR_EACH_4 args
#define wxCALL_FOR_EACH_5_(args) wxCALL_FOR_EACH_5 args
#define wxCALL_FOR_EACH_6_(args) wxCALL_FOR_EACH_6 args
#define wxCALL_FOR_EACH_7_(args) wxCALL_FOR_EACH_7 args
#define wxCALL_FOR_EACH_8_(args) wxCALL_FOR_EACH_8 args
#define wxCALL_FOR_EACH_1(what, x) what(1, x)
#define wxCALL_FOR_EACH_2(what, x, ...) what(2, x) wxCALL_FOR_EACH_1(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_3(what, x, ...) what(3, x) wxCALL_FOR_EACH_2(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_4(what, x, ...) what(4, x) wxCALL_FOR_EACH_3(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_5(what, x, ...) what(5, x) wxCALL_FOR_EACH_4(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_6(what, x, ...) what(6, x) wxCALL_FOR_EACH_5(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_7(what, x, ...) what(7, x) wxCALL_FOR_EACH_6(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_8(what, x, ...) what(8, x) wxCALL_FOR_EACH_7(what, __VA_ARGS__)
#define wxCALL_FOR_EACH_2(what, x, ...) what(2, x) wxCALL_FOR_EACH_1_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_3(what, x, ...) what(3, x) wxCALL_FOR_EACH_2_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_4(what, x, ...) what(4, x) wxCALL_FOR_EACH_3_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_5(what, x, ...) what(5, x) wxCALL_FOR_EACH_4_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_6(what, x, ...) what(6, x) wxCALL_FOR_EACH_5_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_7(what, x, ...) what(7, x) wxCALL_FOR_EACH_6_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_8(what, x, ...) what(8, x) wxCALL_FOR_EACH_7_((what, __VA_ARGS__))
#define wxCALL_FOR_EACH_(N, args) \
wxCONCAT(wxCALL_FOR_EACH_, N) args

View File

@ -35,11 +35,15 @@ public:
private:
CPPUNIT_TEST_SUITE( MiscTestCase );
CPPUNIT_TEST( Assert );
#ifdef HAVE_VARIADIC_MACROS
CPPUNIT_TEST( CallForEach );
#endif // HAVE_VARIADIC_MACROS
CPPUNIT_TEST( Delete );
CPPUNIT_TEST( StaticCast );
CPPUNIT_TEST_SUITE_END();
void Assert();
void CallForEach();
void Delete();
void StaticCast();
@ -75,6 +79,20 @@ void MiscTestCase::Assert()
wxSetAssertHandler(oldHandler);
}
#ifdef HAVE_VARIADIC_MACROS
void MiscTestCase::CallForEach()
{
#define MY_MACRO(pos, str) s += str;
wxString s;
wxCALL_FOR_EACH(MY_MACRO, "foo", "bar", "baz");
CPPUNIT_ASSERT_EQUAL( "foobarbaz", s );
#undef MY_MACRO
}
#endif // HAVE_VARIADIC_MACROS
void MiscTestCase::Delete()
{
// Allocate some arbitrary memory to get a valid pointer: