2014-12-16 4 views
3

가변 매크로 호출을 "중첩 (nest)"할 수 있는지 궁금합니다. 나는 진정으로 GCC와 Clang에 관심이있다. 내 매크로 정의는 다음과 같습니다Variadic 매크로 : 붙여 넣은 토큰의 확장

$(array, addObject, obj); 

작품의 감독 :

/** 
* @brief Invoke an instance method. 
*/ 
#define $(obj, method, ...) \ 
    ({ \ 
     typeof(obj) _obj = obj; \ 
     _obj->interface->method(_obj, ## __VA_ARGS__); \ 
    }) 

나는이 편리 내 OO 프레임 워크 ( https://github.com/jdolan/objectively)의 "인스턴스 메서드를"전화를 사용합니다. 불행히도, 나는이 호출의 중첩을 허용하는 방법을 아직 찾지 못했지만, 어떤 경우에는 매우 유용 할 것이다. 예 :

/** 
* @see MutableSetInterface::addObjectsFromArray(MutableSet *, const Array *) 
*/ 
static void addObjectsFromArray(MutableSet *self, const Array *array) { 

    if (array) { 
     for (size_t i = 0; i < array->count; i++) { 
      $(self, addObject, $(array, objectAtIndex, i)); 
     } 
    } 
} 

내포 된 호출이 결코 확장되지 않기 때문에 위의 중첩 된 가변 매크로 호출은 컴파일되지 않습니다. 이 문제를 해결할 수 있습니까? 아니면 이미 전 처리기를 한계까지 남용 했습니까? :)

+1

', ##'트릭은 이식성이 없으며 gcc와 관련이 있습니다. –

+0

알아. 그것은 Clang에서도 작동합니다. 그것들은 현재 내가 다루어야하는 유일한 두 개의 컴파일러입니다. – jdolan

답변

6

중첩 된 전 처리기 매크로의 일반적인 문제입니다. 전처리 확장 규칙은 매우 신비합니다. 해당 tl; dr은 매크로가 레이어로 확장된다는 것입니다.

#define MI(obj, method, ...) \ 
    ({ \ 
    typeof(obj) _obj = obj; \ 
    _obj->interface->method(_obj, ## __VA_ARGS__); \ 
    }) 

#define M(obj, method, ...) MI(obj, method, __VA_ARGS__) 

// This will now expand properly. 
M(self, addObject, M(array, objectAtIndex, M(foo, bar, i))) 

사이드 노트 : 해결 방법은 매개 변수가 확장 될 수있는 간접 레이어 추가하는 것입니다 $는 C의 기본 소스 문자 세트의 일부가 아니라고 인식을; 아마도 이식성이 없을 것입니다.

+0

', ##'도 이식 할 수 없습니다. –

+0

당신의 대답을 정확하게 이해한다면, 나는 인수가있을 때만'M'이라고 부를 것입니다. 'method' 이외의 인수없이'M'을 호출하려고 시도하면 결과 코드가 파싱되지 않습니다. 즉,'M (self, methodName)'은 컴파일되지 않습니다. 이 올바른지? 추가 인수에 관계없이 올바른 것을 수행하는 단일 "진입 점"을 갖는 방법이 있습니까? – jdolan

+0

(감사합니다. 여기에서 사용하는 특정 기능은 비표준입니다. 내가 언급 한 것처럼 GCC와 Clang에만 관심이 있습니다.) – jdolan