简体   繁体   中英

Macro to repeat a single character multiple number of times

I am learning about macros and I want to know that whether it is possible to create a macro that repeats a given character literal a given number of times. For example:

Input :

repeatMacro('a', 5)

should produce(expand to) the output:

Expected Output:

aaaaa

Similarly, repeatMacro('r', 2) should produce:

rr

If possible, repeatMacro('r') should produce(expand to):

r

I have not worked with macros before so I don't know if this is a very basic thing to do.

I also don't know if there is any other way(other than macros) to do the same. If there is any other way(other than macro) to do this, I would prefer that way instead of using macros.

For example, I know that we can do things like the following with macros:

#define x *
int x func()
{
    int*ptr = new int(4);
    return ptr;
}

So I want to do the same with repeatMacro . Something like shown below:

#define repeatMacro(str, n)  // what should come here for the below example to work
int repeatMacro('*',2) func()
{
    int** ptr = new int*[5]();
    return ptr;
}

The preprocessor doesn't have any way to do anything with character literals like 'a' other than output them as is, so I don't think that form is possible. Instead, we'll need to work with identifier preprocessor tokens like a .

Working with numbers in the preprocessor is always tricky, but Boost.Preprocessor has tools to help.

#include <boost/preprocessor/seq/cat.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/facilities/overload.hpp>

#define REPEAT_MACRO_SEQ_ELEM(z, n, data) (data)
#define REPEAT_MACRO_2(c, n) \
    BOOST_PP_SEQ_CAT(BOOST_PP_REPEAT(n, REPEAT_MACRO_SEQ_ELEM, c))
#define REPEAT_MACRO_1(c) c

#define REPEAT_MACRO(...) \
    BOOST_PP_OVERLOAD(REPEAT_MACRO_, __VA_ARGS__)(__VA_ARGS__)

I've renamed your macro REPEAT_MACRO , because it's common practice to use only uppercase for a preprocessor macro name, giving a hint to the code reader that it's a macro.

REPEAT_MACRO_2 uses BOOST_PP_SEQ_CAT to paste together a sequence of preprocessor tokens. It expects input in the form of a "sequence" like (a)(a)(a)(a)(a) , so we pass it the result of BOOST_PP_REPEAT , using REPEAT_MACRO_SEQ_ELEM as the operator to add the parentheses around the input token.

To take care of allowing REPEAT_MACRO(r) producing just r , there's BOOST_PP_OVERLOAD . It will paste the number of arguments onto the end of the given macro prefix REPEAT_MACRO_ , so that REPEAT_MACRO(c) calls REPEAT_MACRO_1(c) and REPEAT_MACRO(c,n) calls REPEAT_MACRO_2(c,n) .

This solution doesn't really require that the input identifier is just one character, and I'm not sure there's any way to require that. So you also get that REPEAT_MACRO(xyz, 3) gives xyzxyzxyz .

For the case from comments of repeating a * as in function type int repeatMacro(*, 2) func() , you would not want to concatenate the preprocessor tokens, since there's no such token as ** . To get that behavior instead of the identifier-pasting would be instead:

#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/facilities/overload.hpp>

#define REPEAT_MACRO_ID_OP
#define REPEAT_MACRO_2(c, n) BOOST_PP_REPEAT(n, REPEAT_MACRO_ID_OP, c)
#define REPEAT_MACRO_1(c) c

#define REPEAT_MACRO(...) \
    BOOST_PP_OVERLOAD(REPEAT_MACRO_, __VA_ARGS__)(__VA_ARGS__)

I doubt there's any way to get a single macro doing the paste for identifiers and just repetition for punctuation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM