가변 인자 템플릿
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 67번째.
어떤 타입의 arguments든 원하는 개수만큼 받아들이는 function이 필요하다면 어떻게 해야 할까요? 기존 템플릿에서는 필요한 타입 매개변수의 개수를 정확히 지정해야 합니다. 가변 템플릿은 템플릿이 임의의 개수의 템플릿 arguments를 받아들일 수 있도록 하여 이 문제를 해결합니다.
문법은 ...(줄임표)을 사용하여 parameter pack을 생성합니다:
template <typename... Args>
void printAll(Args... args) {
// Args는 템플릿 매개변수 팩입니다
// args는 함수 매개변수 팩입니다
}arguments를 처리하려면 일반적으로 base case와 함께 recursive를 사용합니다. parameter pack은 남은 항목이 없을 때까지 한 번에 하나의 argument씩 확장됩니다:
// 기본 케이스: 인수가 남아 있지 않음
void print() {
std::cout << std::endl;
}
// 재귀 케이스: 첫 번째 인수를 처리하고, 나머지로 재귀
template <typename T, typename... Rest>
void print(T first, Rest... rest) {
std::cout << first << " ";
print(rest...); // 나머지 인수 확장
}
print(1, 3.14, "hello", 'x'); // 출력: 1 3.14 hello x명시적인 재귀 없이 더 간단한 연산을 수행하려면 fold expressions(C++17)을 사용할 수도 있습니다:
template <typename... Args>
auto sum(Args... args) {
return (args + ...); // 폴드 표현식: 모든 인수를 더함
}
std::cout << sum(1, 2, 3, 4) << std::endl; // 출력: 10가변 인자 템플릿은 std::make_unique, std::tuple, std::function과 같은 많은 표준 라이브러리 기능을 구동합니다. 이를 통해 인수의 유형과 개수에 관계없이 작동하는 타입 안전 함수를 만들 수 있습니다.
챌린지
쉬움임의의 개수의 인수를 포함하는 메시지를 처리하기 위해 가변 템플릿을 사용하는 유연한 로깅 시스템을 만들어 보겠습니다. 매개변수 팩을 사용하여 값을 연결하고, 인수의 개수를 세고, 형식이 지정된 출력을 출력하는 유틸리티를 작성합니다.
코드를 두 개의 파일로 구성합니다:
Variadic.h: 여기에서 가변 템플릿 function을 정의합니다.모든 인수를 공백으로 구분하여 출력한 다음 줄바꿈을 출력하는
printAllfunction을 만듭니다. 줄바꿈만 출력하는 기본 case와 첫 번째 인수 및 공백을 출력한 다음 나머지 인수로 재귀 호출하는 재귀 case를 사용하는 재귀적 접근 방식을 활용합니다.전달된 인수의 개수를 반환하는
countArgsfunction을 만듭니다.sizeof...를 사용하여 parameter pack의 크기를 가져옵니다.모든 숫자 인수를 더하고 결과를 반환하는
sumfunction을 만듭니다.+operator를 사용하는 fold expression을 활용합니다.모든 숫자 인수를 곱하고 결과를 반환하는
productfunction을 만듭니다.*operator를 사용하는 fold expression을 활용합니다.main.cpp: 네 개의 입력을 읽습니다(각각 별도의 줄에 입력):- 정수
- double
- 문자열
- 문자
다음과 같이 가변 템플릿을 시연합니다:
- 네 개의 모든 입력을 사용하여
printAll을 호출하고 결과를 출력합니다. - 정수, double, 문자를 사용하여
countArgs를 호출할 때 인수의 개수를 출력합니다:Argument count: <count> - 정수, double, 값 10과 5의 합을 계산한 다음 출력합니다:
Sum: <result> - 정수와 값 2 및 3의 곱을 계산한 다음 출력합니다:
Product: <result> - 문자열만 사용하여
printAll을 호출합니다(단일 인수). - 인수 없이
printAll을 호출합니다(줄바꿈만 출력해야 함).
예를 들어 입력이 5, 2.5, Hello, X인 경우:
5 2.5 Hello X
Argument count: 3
Sum: 22.5
Product: 30
Hello
printAll이 네 개의 인수부터 0개까지, 서로 다른 타입의 임의 개수 인수를 어떻게 처리하는지 확인해 보세요. sum과 product function은 fold expression을 사용하여 명시적인 재귀 없이 모든 값을 우아하게 결합합니다. countArgs function은 sizeof...가 컴파일 시점에 pack의 크기를 어떻게 알려 주는지 보여 줍니다.
직접 해보기
#include <iostream>
#include <string>
#include "Variadic.h"
using namespace std;
int main() {
// 입력 읽기
int intVal;
double doubleVal;
string strVal;
char charVal;
cin >> intVal;
cin >> doubleVal;
cin >> strVal;
cin >> charVal;
// TODO: 네 개의 입력 모두로 printAll 호출
// TODO: Print argument count using countArgs with intVal, doubleVal, and charVal
// Format: "Argument count: <count>"
// TODO: intVal, doubleVal, 10, 5의 합을 계산하고 출력
// 형식: "Sum: <result>"
// TODO: intVal, 2, 3의 곱을 계산하고 출력
// 형식: "Product: <result>"
// TODO: 문자열만으로 printAll 호출
// TODO: 인수 없이 printAll 호출
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C++ 컴파일러