user1899020
user1899020

Reputation: 13575

How to declare type for each macro argument?

For example

 DECL_TYPE(a) becomes decltype(a)
 DECL_TYPE(a, b) becomes decltype(a), decltype(b)
 DECL_TYPE(a, b, c) becomes decltype(a), decltype(b), decltype(c)

How to define the macro DECL_TYPE?

Upvotes: 0

Views: 433

Answers (1)

Cheers and hth. - Alf
Cheers and hth. - Alf

Reputation: 145279

Well, let's start with the basic issue of counting the number of arguments.

It can go like this:

nargs.h
#pragma once
// Copyright (c) 2013 Alf P. Steinbach.
//
// The MM_NARGS macro evaluates to the number of arguments that have been
// passed to it.
//
// Based on original code by Laurent Deniau,
// "__VA_NARG__," 17 January 2006, <comp.std.c> (29 November 2007).
// https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c/d-6Mj5Lko_s

#include <rfc/macro_magic/invoke.h>         // MM_INVOKE
#include <rfc/macro_magic/concat.h>         // MM_CONCAT

#define MM_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63,N,...) N

#define MM_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0

#ifdef MM_USE_ORIGINAL_DEFINITION
    #define MM_NARGS_(...) MM_ARG_N( __VA_ARGS__ )
    #define MM_NARGS( ...) MM_NARGS_( __VA_ARGS__, MM_RSEQ_N() )
#else
    #define MM_NARGS_AUX( ... ) MM_INVOKE( MM_ARG_N, ( __VA_ARGS__ ) )
    #define MM_NARGS( ... )     MM_NARGS_AUX( __VA_ARGS__, MM_RSEQ_N() )
#endif

… using these two helper files:

invoke.h
#pragma once
// Copyright (c) 2013 Alf P. Steinbach.

#define MM_INVOKE( macro, args ) macro args
#define MM_INVOKE_B( macro, args ) macro args     // For nested invocation with g++.
concat.h
#pragma once
// Copyright (c) 2013 Alf P. Steinbach.

#define MM_CONCAT__( a, b )     a ## b
#define MM_CONCAT_( a, b )      MM_CONCAT__( a, b )
#define MM_CONCAT( a, b )       MM_CONCAT_( a, b )

It's been quite some time since I fiddled with this code and I seem to recall some problem with the concatenation. But at least there have existed contexts where the above code has worked. It probably works in general.


Macro to apply a given macro to a sequence of arguments:

apply.h
#pragma once
// Copyright (c) 2013 Alf P. Steinbach.

#include <rfc/macro_magic/nargs.h>  // MM_INVOKE, MM_INVOKE_B, MM_CONCAT, MM_NARGS

#define MM_APPLY_1( macroname, a1 ) \
    MM_INVOKE_B( macroname, (a1) )

#define MM_APPLY_2( macroname, a1, a2 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_1( macroname, a2 )

#define MM_APPLY_3( macroname, a1, a2, a3 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_2( macroname, a2, a3 )

#define MM_APPLY_4( macroname, a1, a2, a3, a4 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_3( macroname, a2, a3, a4 )

#define MM_APPLY_5( macroname, a1, a2, a3, a4, a5 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_4( macroname, a2, a3, a4, a5 )

#define MM_APPLY_6( macroname, a1, a2, a3, a4, a5, a6 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_5( macroname, a2, a3, a4, a5, a6 )

#define MM_APPLY_7( macroname, a1, a2, a3, a4, a5, a6, a7 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_6( macroname, a2, a3, a4, a5, a6, a7 )

#define MM_APPLY_8( macroname, a1, a2, a3, a4, a5, a6, a7, a8 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_7( macroname, a2, a3, a4, a5, a6, a7, a8 )

#define MM_APPLY_9( macroname, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_8( macroname, a2, a3, a4, a5, a6, a7, a8, a9 )

#define MM_APPLY_10( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_9( macroname, a2, a3, a4, a5, a6, a7, a8, a9, a10 )

#define MM_APPLY_11( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_10( macroname, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 )

#define MM_APPLY_12( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_11( macroname, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 )

#define MM_APPLY_13( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_12( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13 \
        )

#define MM_APPLY_14( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_13( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14 \
        )

#define MM_APPLY_15( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_14( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15 \
        )

#define MM_APPLY_16( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15, a16 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_15( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15, a16 \
        )

#define MM_APPLY_17( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15, a16, a17 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_16( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15, a16, a17 \
        )

#define MM_APPLY_18( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15, a16, a17, a18 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_17( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15, a16, a17, a18 \
        )

#define MM_APPLY_19( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15, a16, a17, a18, a19 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_18( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15, a16, a17, a18, a19 \
        )

#define MM_APPLY_20( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_19( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15, a16, a17, a18, a19, a20 \
        )

#define MM_APPLY_21( macroname, \
    a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
    a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, \
    a21 \
    ) \
    MM_INVOKE_B( macroname, (a1) ) \
    MM_APPLY_20( macroname, \
        a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, \
        a12, a13, a14, a15, a16, a17, a18, a19, a20, a21 \
        )

#define MM_APPLY( macroname, ... ) \
    MM_INVOKE( \
        MM_CONCAT( MM_APPLY_, MM_NARGS( __VA_ARGS__ ) ), \
        ( macroname, __VA_ARGS__ ) \
        )

Now isn't that nice.

So little repetition.


An example use case:

#ifdef _WIN32
    namespace cppx{ typedef wchar_t Raw_syschar; }        // Implies UTF-16 encoding.
#   define CPPX_SYSCHAR_IS_WIDE                 1
#   define CPPX_WITH_SYSCHAR_PREFIX_( lit )     L##lit
#else
    namespace cppx{ typedef char Raw_syschar; }           // Implies UTF-8 encoding.
#   define CPPX_SYSCHAR_IS_WIDE                 0
#   define CPPX_WITH_SYSCHAR_PREFIX_( lit )     lit
#endif

#define CPPX_WITH_SYSCHAR_PREFIX( ... ) \
    MM_APPLY( CPPX_WITH_SYSCHAR_PREFIX_, __VA_ARGS__ )

#define CPPX_AS_SYSCHAR( ... ) \
    ::cppx::typed( CPPX_WITH_SYSCHAR_PREFIX( __VA_ARGS__ ) )

#define CPPX_U      CPPX_AS_SYSCHAR
#define CPPX_RAW_U  CPPX_WITH_SYSCHAR_PREFIX

which allows one to write e.g.

auto const x = CPPX_U
(
    "First line\n",
    "Second line"
);

and have it translated to

auto const x = cppx::typed( L"First line\n" L"Second line" );

In your particular example case you would define code like

#define APPLY_DECL_TYPE( x ) decltype( x ),
#define DECL_TYPE( ... ) MM_APPLY( APPLY_DECL_TYPE, __VA_ARGS__ )

You provide too little context to decide on a proper strategy for handling comma (or lack thereof) after last argument.

But I think this should be enough to put you on the right (or a working) track.

Final thought, it does sound as if your problem would be better addressed by using variadic templates rather than macros. Macros are for those cases that can't be handled otherwise, like the string literals example shown above. But again, you provide too little context to say.

Upvotes: 1

Related Questions