developer tip

C / C ++ 매크로의 쉼표

copycodes 2020. 8. 29. 11:24
반응형

C / C ++ 매크로의 쉼표


이와 같은 매크로가 있다고 가정 해 보겠습니다.

#define FOO(type,name) type name

다음과 같이 사용할 수 있습니다.

FOO(int, int_var);

그러나 항상 그렇게 간단하지는 않습니다.

FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2

물론 우리는 할 수 있습니다 :

 typedef std::map<int, int> map_int_int_t;
 FOO(map_int_int_t, map_var); // OK

인체 공학적이지 않습니다. Plus 유형 비 호환성을 처리해야합니다. 이 문제를 매크로로 해결하는 방법을 알고 계십니까?


각괄호도 나타낸다 (또는 발생) 할 수 있기 때문에, 비교 연산자 <, >, <=>=는 괄호하는 것처럼, 매크로 확장 각괄호 내부 쉼표를 무시할 수 없다. (대괄호와 중괄호는 일반적으로 균형 잡힌 쌍으로 발생하지만 이는 또한 문제입니다.) 매크로 인수를 괄호로 묶을 수 있습니다.

FOO((std::map<int, int>), map_var);

문제는 매개 변수가 매크로 확장 내에서 괄호로 묶여있어 대부분의 컨텍스트에서 유형으로 읽히지 못하게한다는 것입니다.

이 문제를 해결하는 좋은 방법은 C ++에서 함수 유형을 사용하여 괄호로 묶인 유형 이름에서 유형 이름을 추출 할 수 있다는 것입니다.

template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
FOO((std::map<int, int>), map_var);

함수 유형을 형성하면 추가 괄호를 무시하므로 유형 이름에 쉼표가 포함되지 않은 괄호를 포함하거나 포함하지 않고이 매크로를 사용할 수 있습니다.

FOO((int), int_var);
FOO(int, int_var2);

물론 C에서는 유형 이름이 괄호 밖에 쉼표를 포함 할 수 없기 때문에 이것이 필요하지 않습니다. 따라서 다국어 매크로의 경우 다음과 같이 작성할 수 있습니다.

#ifdef __cplusplus__
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
#else
#define FOO(t,name) t name
#endif

괄호를 사용할 수없고 Mike의 SINGLE_ARG 솔루션이 마음에 들지 않으면 COMMA를 정의하십시오.

#define COMMA ,

FOO(std::map<int COMMA int>, map_var);

이것은 또한 다음과 같이 일부 매크로 인수를 문자열 화하려는 경우에도 도움이됩니다.

#include <cstdio>
#include <map>
#include <typeinfo>

#define STRV(...) #__VA_ARGS__
#define COMMA ,
#define FOO(type, bar) bar(STRV(type) \
    " has typeid name \"%s\"", typeid(type).name())

int main()
{
    FOO(std::map<int COMMA int>, std::printf);
}

인쇄합니다 std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE".


전처리 기가 가변 매크로를 지원하는 경우 :

#define SINGLE_ARG(...) __VA_ARGS__
#define FOO(type,name) type name

FOO(SINGLE_ARG(std::map<int, int>), map_var);

그렇지 않으면 좀 더 지루합니다.

#define SINGLE_ARG2(A,B) A,B
#define SINGLE_ARG3(A,B,C) A,B,C
// as many as you'll need

FOO(SINGLE_ARG2(std::map<int, int>), map_var);

그냥 정의 FOO

#define UNPACK( ... ) __VA_ARGS__

#define FOO( type, name ) UNPACK type name

그런 다음 항상 유형 인수를 괄호로 묶어 호출하십시오.

FOO( (std::map<int, int>), map_var );

It can of course be a good idea to exemplify the invocations in a comment on the macro definition.


There are at least two ways to do this. First, you can define a macro that takes multiple arguments:

#define FOO2(type1, type2, name) type1, type2, name

if you do that you may find that you end up defining more macros to handle more arguments.

Second, you can put parentheses around the argument:

#define FOO(type, name) type name
F00((std::map<int, int>) map_var;

if you do that you may find that the extra parentheses screw up the syntax of the result.


This is possible with P99:

#include "p99/p99.h"
#define FOO(...) P99_ALLBUTLAST(__VA_ARGS__) P99_LAST(__VA_ARGS__)
FOO()

The code above effectively strips only the last comma in the argument list. Check with clang -E (P99 requires a C99 compiler).


The simple answer is that you can't. This is a side effect of the choice of <...> for template arguments; the < and > also appear in unbalanced contexts so the macro mechanism couldn't be extended to handle them like it handles parentheses. (Some of the committee members had argued for a different token, say (^...^), but they weren't able to convince the majority of the problems using <...>.)

참고URL : https://stackoverflow.com/questions/13842468/comma-in-c-c-macro

반응형