Namespaces
Variants

Variadic arguments

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

함수가 임의의 수의 추가 인수를 허용하도록 합니다.

함수는 해당 매개변수 목록 의 마지막 매개변수가 생략 부호( ... )인 경우 가변 인자 함수입니다.

줄임표 앞의 쉼표는 생략할 수 있습니다. (C++26에서 사용 중단됨)
// 함수는 다음과 같이 선언됩니다
int printx(const char* fmt, ...);
int printx(const char* fmt...); // 위와 동일하지만 C++26부터 사용이 권장되지 않음
// 하나 이상의 인수로 호출될 수 있습니다:
printx("hello world");
printx("a=%d b=%d", a, b);
int printy(..., const char* fmt); // 오류: ...은 마지막 매개변수로만 사용 가능합니다
int printz(...); // 유효하지만, 인수에 이식성 있게 접근할 수 없습니다

이것은 parameter pack 확장과는 다릅니다. parameter pack 확장은 매개변수 선언자의 일부인 생략 부호로 표시되는 반면, "가변 인자" 생략 부호는 단독 매개변수로 사용됩니다. std::is_function 의 경우와 같이, parameter pack 확장과 "가변 인자" 생략 부호 모두 함수 템플릿 선언에 나타날 수 있습니다.

(C++11부터)

목차

기본 인수 승격

가변 인수 함수가 호출될 때, lvalue-to-rvalue, array-to-pointer, function-to-pointer 변환 이 수행된 후, 가변 인수 목록의 일부인 각 인수는 기본 인수 승격 이라고 알려진 추가 변환을 거칩니다:

(C++11 이후)
  • float 인수는 부동소수점 승격 에서와 같이 double 로 변환됩니다.
  • bool , char , short , 그리고 범위 없는 열거형은 정수 승격 에서와 같이 int 또는 더 넓은 정수 타입으로 변환됩니다.

Non-POD 클래스 타입 (C++11 이전) 범위 지정 열거형 및 적격한 비트리비얼 복사 생성자, 적격한 비트리비얼 이동 생성자, 또는 비트리비얼 소멸자를 가진 클래스 타입 (C++11 이후) 은 구현에서 정의된 의미론을 갖는 잠재적으로 평가되는 호출에서 조건부 지원되며(이러한 타입들은 항상 평가되지 않는 호출 에서 지원됩니다).

가변 인수 매개변수는 오버로드 해결 목적상 가장 낮은 순위를 가지므로, SFINAE 에서 흔히 만능 안전망(fallback)으로 사용됩니다.

가변 인자를 사용하는 함수 본문 내에서, 이러한 인자들의 값은 <cstdarg> 라이브러리 기능 을 사용하여 접근할 수 있습니다:

헤더 파일에 정의됨 <cstdarg>
가변 인수 함수 인수에 대한 접근을 활성화
(함수 매크로)
다음 가변 인수 함수 인수에 접근
(함수 매크로)
(C++11)
가변 인수 함수 인수의 복사본 생성
(함수 매크로)
가변 인수 함수 인수의 순회 종료
(함수 매크로)
va_start , va_arg , va_end , 및 va_copy 에 필요한 정보 보유
(typedef)

va_start 매크로의 동작은 생략부호 바로 앞의 마지막 매개변수가 참조 타입이거나, 기본 인수 승격 결과 타입과 호환되지 않는 타입인 경우 정의되지 않습니다.

만약 pack expansion 이나 lambda capture 에서 생성된 엔티티가 va_start 의 마지막 매개변수로 사용되면, 프로그램은 형식이 잘못되었으며 진단이 필요하지 않습니다.

(C++11부터)

대안

  • 가변 인수 템플릿 은 가변 개수의 인수를 받는 함수를 생성하는 데에도 사용될 수 있습니다. 이는 인수의 타입에 제한을 두지 않으며, 정수 및 부동 소수점 승격을 수행하지 않고 타입 안전성을 제공하므로 종종 더 나은 선택입니다.
  • 모든 가변 인수가 공통 타입을 공유하는 경우, std::initializer_list 는 (비록 다른 구문을 사용하지만) 가변 인수에 접근하기 위한 편리한 메커니즘을 제공합니다. 그러나 이 경우 std::initializer_list 가 해당 요소들에 대한 const 포인터만 제공할 수 있으므로 인수들을 수정할 수 없습니다.
(C++11부터)

참고 사항

C 프로그래밍 언어에서 C23 이전까지는 생략부호 매개변수 앞에 적어도 하나의 명명된 매개변수가 나타나야 하므로, R printz ( ... ) ; 는 C23 이전에는 유효하지 않습니다. C++에서는 이러한 함수에 전달된 인수에 접근할 수 없음에도 이 형식이 허용되며, SFINAE 에서 폴백 오버로드로 흔히 사용되며, 오버로드 해결 에서 생략부호 변환의 최하위 우선순위를 활용합니다.

가변 인수에 대한 이 구문은 1983년 C++에서 쉼표 없이 줄임표 앞에 도입되었습니다. C89가 C++에서 함수 프로토타입을 채택했을 때, 쉼표를 요구하는 구문으로 대체했습니다. 호환성을 위해 C++98은 C++ 스타일 f ( int n... ) 와 C 스타일 f ( int n, ... ) 모두를 허용합니다. 원래의 C++ 스타일 문법은 C++26부터 사용이 권장되지 않습니다.

쉼표를 축약 함수 템플릿에서 사용하여 생략 부호가 가변 템플릿 대신 가변 함수를 나타내도록 할 수 있습니다:

void f1 ( auto ... ) ; // same as template<class... Ts> void f3(Ts...)
void f2 ( auto , ... ) ; // same as template<class T> void f3(T, ...)

(C++20부터)

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 506 C++98 비-POD 클래스 인수를
생략부호에 전달하면 정의되지 않은 동작이 발생함
해당 인수 전달은
구현체 정의 의미 체계를 가진
조건부 지원으로 변경됨
CWG 634 C++98 조건부 지원 클래스 타입으로 인해
일부 SFINAE 관용구가 작동하지 않음
평가되지 않은 컨텍스트에서는 항상 지원됨
CWG 2247 C++11 매개변수 팩이나 람다 캡처를
va_start 에 전달하는 데 제한이 없었음
진단 없이
잘못된 형식으로 규정됨
CWG 2347 C++11 범위 있는 열거형을 생략부호에 전달할 때
기본 인수 승격이 적용되는지 명확하지 않았음
범위 있는 열거형 전달은
구현체 정의 의미 체계를 가진
조건부 지원으로 변경됨

참고 항목

C documentation for Variadic arguments
C documentation for Implicit conversions