source

C/C++ 매크로의 쉼표

goodcode 2022. 8. 10. 22:19
반응형

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

인체공학적이지 않은 방법이죠게다가 타입의 비호환성도 취급할 필요가 있습니다.매크로로 해결할 방법을 알고 계십니까?

괄호를 사용할 수 없고 Mike의 SINGLE_ARG 솔루션이 마음에 들지 않으면 쉼표를 정의하기만 하면 됩니다.

#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".

꺾쇠 괄호는 비교 연산자를 나타낼 수도 있기 때문에<,>,<=그리고.>=, 매크로 확장은 괄호 안에서처럼 괄호 안의 쉼표를 무시할 수 없습니다.(이것은, 대괄호나 대괄호에서도 문제가 됩니다만, 일반적으로 밸런스 페어로서 발생합니다).macro 인수는 괄호로 묶을 수 있습니다.

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

프리프로세서가 가변 매크로를 지원하는 경우:

#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

그런 다음 항상 type 인수 주위에 괄호를 사용하여 호출합니다.

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

물론 매크로 정의에 대한 코멘트에서 호출을 예시하는 것은 좋은 생각일 수 있다.

간단한 대답은 당신은 할 수 없다는 것이다.이것은 선택으로 인한 부작용이다.<...>템플릿 인수의 경우;<그리고.>또한 불균형한 맥락에서 나타나기 때문에 매크로 메커니즘이 괄호를 처리하는 것처럼 그들을 처리하도록 확장될 수 없었다. (몇몇 위원회 구성원은 다른 토큰을 주장했다, 예를 들어(^...^)하지만, 그들은 이 프로그램을 사용하여 대부분의 문제를 납득시킬 수는 없었다.<...>.)

적어도 두 가지 방법이 있습니다.먼저 여러 인수를 사용하는 매크로를 정의할 수 있습니다.

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

이렇게 하면 더 많은 인수를 처리하기 위해 더 많은 매크로를 정의할 수 있습니다.

둘째, 인수 주위에 괄호를 둘 수 있습니다.

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

이렇게 하면 추가 괄호가 결과의 구문을 망칠 수 있습니다.

이것은, P99 로 가능합니다.

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

위의 코드는 인수 목록의 마지막 쉼표만 효과적으로 삭제합니다.clang -E(P99에는 C99 컴파일러가 필요합니다).

언급URL : https://stackoverflow.com/questions/13842468/comma-in-c-c-macro

반응형