2011-09-25 9 views
3

libC++에서 GCC의 구현되지 않은 항상 인라이닝 가변 인자 함수를 무시하기 위해 가변 인자 함수 (snprintf와 같은, 더 정확하게, * _l 변수)를 변수로 감쌀 수 있다고 생각했습니다. 유사한 효과를 얻을 수있는 템플릿. 인스턴스화는 variadic 함수의 varargs를 채울 것이므로 함수가 멋지게 인라인 될 수 있습니다. 문제는 variadic 템플릿을 작성하는 것에 대해 제일 먼저 알지 못하기 때문에 템플릿 인수를 별도의 인수로 변환하는 방법을 확실히 알지 못합니다.가변 인자 템플릿을 가변 인자 함수로 묶기

int __sprintf_l(char *__s, locale_t __l, const char *__format, ...) { 
    va_list __va; 
    va_start(__va, __format); 
    int __res = vsprintf_l(__s, __l, __format, __va); 
    va_end(__va); 
    return __res; 
} 
내가 대체하고 싶습니다

양식의 뭔가입니다 :

template<typename... Args> 
int __sprintf_l(char *__s, locale_t __l, const char *__format, Args... args) { 
    int __res = vsprintf_l(__s, __l, __format, args...); 
    return __res; 
} 

이 작동하지 않는 때문에

내가 대체 할 찾고 있어요 코드의 형식은 확장 된 args...으로 type에서 va_list {aka char*}으로 변환 할 수 없습니다. 방법이 없다면 하워드를 신뢰하고 필요한 코드의 양을 실질적으로 두 배로 늘릴 수있는 하나, 두 개의 인수 인 항상 인라인 템플릿을 구현해야 할 것입니다.

편집 : 아마도 std::tupleargs으로 변환하는 방법은 va_list에 포함됩니까?

+0

'va_list' 구현의 구현이 정의되어 있지 않습니까? 그래서 변환 할 수있는 이식성있는 방법이 없습니다. 맞습니까? 또한'boost :: format'이 대안이 될 수 있습니다. – pmr

+1

분명히하자면,'args'는 전혀 std :: tuple이 아닙니다. 그것은 고유 한 실체이며, 나는 손을 잊지 않는 이름을 가지고 있습니다. 'args ...'는 본질적으로'arg0, arg1, arg2, ..., argN'으로 확장됩니다; 즉,'vsprintf_l '이 하나의'va_list' 객체가 아니라 가변 인자를 받아 들인다면, 당신이했던 것은 작동 할 것입니다. –

답변

3

내가 묻는 질문은 혼란 스럽기 때문에 다시 말해 보겠습니다.

variadic 템플릿을 사용하여 가변 함수를 인라이닝하는 기능을 작성하고 싶습니다.

할 수 없습니다. va_args은 스택의 첫 번째 매개 변수에 void *로 구현되는 경우가 많습니다 (variadic 함수는 이러한 이유 때문에 적어도 하나의 가변 인수가 필요합니다).

올바른 위치에 매개 변수를 가져 오려면 호출 스택을 조작해야합니다. 이제 variadic 템플릿 함수의 인수가 va_args과 같은 위치의 스택에 있지만 템플릿 함수가 인라인되지 않아야합니다.

나는 가변적 인 함수를 항상 인라이닝하는 이유는 표준 스택 레이아웃을 가정하는 va_args 구현 때문에 구현되지 않는다고 생각합니다. 컴파일러가 해당 함수를 인라인하려면 스택 공간을 할당하고 매개 변수를 제자리에 복사해야합니다. 저장하는 유일한 방법은 실제 jmpret 명령입니다.

인라인 할 때 얻을 수있는 이점의 절반이 증발합니다. 또한 컴파일러는 매개 변수 전달 코드 (컴파일러 코드)를 가변 함수의 강제 인라인으로 일반 함수 호출과 함께 사용하기위한보다 일반적인 위치로 호이스트해야합니다. 다시 말해 제어의 흐름이 상당히 작거나 전혀 효과적이지 못합니다.

1

당신은 당신의 자신의 sprintf_l

int __noninlined_sprintf_l(char *__s, locale_t __l, const char *__format, ...) { 
    va_list __va; 
    va_start(__va, __format); 
    int __res = vsprintf_l(__s, __l, __format, __va); 
    va_end(__va); 
    return __res; 
} 

를 구현하고 대신

template<typename... Args> 
int __sprintf_l(char *__s, locale_t __l, const char *__format, Args... args) { 
    int __res = __noninlined_sprintf_l(__s, __l, __format, args...); 
    return __res; 
} 
+0

이것은 내가 끝내었지만, 위에서 말한 deft_code로 인해 완전히 작동하지 않았습니다 ... 코드가 사용 사례를 위해 제거되었으므로 문제가있는 코드가 사용되지 않아 직접적인 문제가 해결되었습니다. – rubenvb

0
template<typename... T> 
int 
variadic(char* s, locale_t locale, const char* format, T&&... t) 
{ 
    return __sprintf_l(s, locale, format, std::forward<T>(t)...); 
} 

그런 다음 variadic(s, l, "%d %s", 42, "Hello")를 호출하면 __sprintf_l(s, l, "%d %s", 42, "Hello")에 대한 호출이 발생할 것이라고를 호출 할 수있다.

+0

나는 코드를 좋아하지만 이것은 질문 한 내용이 아닙니다. 나는 질문을 잘못 말하면서 -1로 갈 수 없다. –

관련 문제