์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐ŸŽฏ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ๊ณผ ํด๋“œ ํ‘œํ˜„์‹ โ€” C++ ๋งˆ๋ฒ•์‚ฌ๊ฐ€ ๋˜๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ๊ธธ
C++ ์‹ฌํ™” ๊ฐœ๋…

๐ŸŽฏ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ๊ณผ ํด๋“œ ํ‘œํ˜„์‹ โ€” C++ ๋งˆ๋ฒ•์‚ฌ๊ฐ€ ๋˜๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ๊ธธ

Variadic Templates & Fold Expressions๋ฅผ ์นœ๊ตฌ์ฒ˜๋Ÿผ ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ํŒŒํ—ค์ณ๋ณด์ž! ๐Ÿš€

์•ผ, ์†”์งํžˆ ๋งํ•ด๋ณผ๊ฒŒ. C++ ๊ณต๋ถ€ํ•˜๋‹ค๊ฐ€ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ(Variadic Templates)์ด๋ผ๋Š” ๋‹จ์–ด ์ฒ˜์Œ ๋ดค์„ ๋•Œ ์–ด๋–ค ๋А๋‚Œ์ด์—ˆ์–ด? ๐Ÿ˜…
"์ด๊ฒŒ ๋ญ” ์†Œ๋ฆฌ์•ผ..." ํ•˜๊ณ  ์ฐฝ ๋‹ซ๊ณ  ์‹ถ์—ˆ์ง€? ๋‚˜๋„ ๊ทธ๋žฌ์–ด. ๊ทผ๋ฐ ํ•œ ๋ฒˆ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ณ  ๋‚˜๋ฉด ์ง„์งœ ์ด๊ฑฐ ์—†์ด ์–ด๋–ป๊ฒŒ ์ฝ”๋”ฉํ–ˆ๋‚˜ ์‹ถ์„ ์ •๋„๋กœ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ.

์˜ค๋Š˜์€ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ๊ณผ C++17์—์„œ ๋“ฑ์žฅํ•œ ํด๋“œ ํ‘œํ˜„์‹(Fold Expressions)์„ ์™„์ „ํžˆ ๋œฏ์–ด๋ณผ ๊ฑฐ์•ผ. ์ฝ”๋“œ ์˜ˆ์ œ ๋นต๋นตํ•˜๊ฒŒ ๋„ฃ๊ณ , ๊ฐœ๋…๋„ ์‰ฝ๊ฒŒ ํ’€์–ด์ค„ ํ…Œ๋‹ˆ๊นŒ ๋๊นŒ์ง€ ๋”ฐ๋ผ์™€๋ด! ๐Ÿ’ช

C++ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ & ํด๋“œ ํ‘œํ˜„์‹ ๊ฐœ๋…๋„ ํ•จ์ˆ˜ ํ˜ธ์ถœ sum(1, 2, 3, 4, 5) ์ธ์ž ๊ฐœ์ˆ˜ ์ž์œ ! ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ template<typename... Args> ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ ์ „๊ฐœ Args... / args... ์žฌ๊ท€ or ํด๋“œ๋กœ ์ฒ˜๋ฆฌ ํด๋“œ ํ‘œํ˜„์‹ (C++17 ์ด์ƒ) (args + ...) (... + args) ๋‹จ ํ•œ ์ค„๋กœ ์ „๊ฐœ! ์žฌ๊ท€ ์—†์ด ๊น”๋”ํ•˜๊ฒŒ ๊ฒฐ๊ณผ๊ฐ’ 15 1+2+3+4+5 ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ชจ๋“  ๊ฒƒ์ด ๊ฒฐ์ •๋˜๋Š” ์ œ๋กœ ์˜ค๋ฒ„ํ—ค๋“œ ๋งˆ๋ฒ•! โœจ ํƒ€์ž… ์•ˆ์ „์„ฑ + ์œ ์—ฐ์„ฑ + ์„ฑ๋Šฅ = C++ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์˜ 3๋ฐ•์ž

๐Ÿค” ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์ด ์™œ ํ•„์š”ํ•ด?

๋จผ์ € ๋ฐฐ๊ฒฝ๋ถ€ํ„ฐ ์ดํ•ดํ•ด๋ณด์ž. ์˜›๋‚  C ์–ธ์–ด ์‹œ์ ˆ์—๋„ ๊ฐ€๋ณ€ ์ธ์ž ํ•จ์ˆ˜๊ฐ€ ์žˆ์—ˆ์–ด. printf ๊ฐ™์€ ๊ฑฐ ๋ง์ด์•ผ. ๊ทผ๋ฐ ๊ทธ๊ฑด ํƒ€์ž… ์•ˆ์ „์„ฑ์ด ์ „ํ˜€ ์—†์—ˆ์–ด. ์ž˜๋ชป๋œ ํƒ€์ž… ๋„˜๊ธฐ๋ฉด ๋Ÿฐํƒ€์ž„์— ํ„ฐ์ง€๊ฑฐ๋‚˜ ์ด์ƒํ•œ ๊ฐ’ ๋‚˜์˜ค๊ณ ... ์ง„์งœ ์ง€๋ขฐ๋ฐญ์ด์—ˆ์ง€.

๐Ÿ•ฐ๏ธ ์˜›๋‚  ๋ฐฉ์‹ (C ์Šคํƒ€์ผ ๊ฐ€๋ณ€ ์ธ์ž)

#include <cstdarg>

int sum_old(int count, ...) {
    va_list args;
    va_start(args, count);
    int total = 0;
    for (int i = 0; i < count; i++) {
        total += va_arg(args, int);  // ํƒ€์ž…์„ ์ง์ ‘ ๋ช…์‹œํ•ด์•ผ ํ•จ!
    }
    va_end(args);
    return total;
}

// ์‚ฌ์šฉ: sum_old(3, 1, 2, 3)
// ๋ฌธ์ œ: ํƒ€์ž… ํ‹€๋ ค๋„ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ชป ์žก์Œ ๐Ÿ˜ฑ

์ด ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ ์ด ๋ญ”์ง€ ์•Œ์•„? count๋ฅผ ์ง์ ‘ ๋„˜๊ฒจ์•ผ ํ•˜๊ณ , ํƒ€์ž…๋„ ์ง์ ‘ ๋ช…์‹œํ•ด์•ผ ํ•˜๊ณ , ์‹ค์ˆ˜ํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๊ฐ€ ๋‚˜. ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ „ํ˜€ ๋„์™€์ฃผ์งˆ ์•Š์•„.

๊ทธ๋ž˜์„œ C++11์—์„œ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ(Variadic Templates)์ด ๋“ฑ์žฅํ–ˆ์–ด! ์ด๊ฑด ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ฐจ์›์˜ ์ด์•ผ๊ธฐ์•ผ. ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ชจ๋“  ํƒ€์ž…์ด ๊ฒฐ์ •๋˜๊ณ , ํƒ€์ž… ์•ˆ์ „์„ฑ์ด ์™„๋ฒฝํ•˜๊ฒŒ ๋ณด์žฅ๋ผ. ๐ŸŽ‰


๐Ÿ“ฆ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ ๊ธฐ์ดˆ โ€” ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ์ด๋ž€?

๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์˜ ํ•ต์‹ฌ ๊ฐœ๋…์€ ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ(Parameter Pack)์ด์•ผ. ์ด๋ฆ„์ด ์ข€ ๋‚ฏ์„ค์ง€? ์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด "์—ฌ๋Ÿฌ ๊ฐœ์˜ ํƒ€์ž…์ด๋‚˜ ๊ฐ’์„ ํ•˜๋‚˜์˜ ์ด๋ฆ„์œผ๋กœ ๋ฌถ์–ด๋†“์€ ๊ฒƒ"์ด์•ผ.

ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ์˜ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜

์ข…๋ฅ˜ ๋ฌธ๋ฒ• ์˜๋ฏธ
ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ typename... Args ์—ฌ๋Ÿฌ ํƒ€์ž…์„ ๋ฌถ์Œ
ํ•จ์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ Args... args ์—ฌ๋Ÿฌ ๊ฐ’์„ ๋ฌถ์Œ
๐Ÿ”ฐ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ

// ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ ํ•จ์ˆ˜ ์„ ์–ธ
template<typename... Args>
void printAll(Args... args) {
    // args๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ
    // ์—ฌ๊ธฐ์„œ ์–ด๋–ป๊ฒŒ ์“ฐ๋ƒ๊ฐ€ ํ•ต์‹ฌ!
}

์—ฌ๊ธฐ์„œ typename... Args์˜ ...์ด ํ•ต์‹ฌ์ด์•ผ. ์ด ์  ์„ธ ๊ฐœ(...)๊ฐ€ "0๊ฐœ ์ด์ƒ์˜ ํƒ€์ž…"์„ ์˜๋ฏธํ•ด. ๊ทธ๋ฆฌ๊ณ  Args... args๋Š” ๊ทธ ํƒ€์ž…๋“ค์— ๋Œ€์‘ํ•˜๋Š” ๊ฐ’๋“ค์˜ ํŒฉ์ด์•ผ.

๊ทผ๋ฐ ์ด ํŒฉ์„ ๊ทธ๋ƒฅ ์“ธ ์ˆ˜๋Š” ์—†์–ด. ํŒฉ ์ „๊ฐœ(Pack Expansion)๋ผ๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•ด. ํŒฉ ๋’ค์— ...์„ ๋ถ™์ด๋ฉด ํŒฉ์ด ํŽผ์ณ์ง€๋Š” ๊ฑฐ์•ผ!

๐Ÿ“Œ ํŒฉ ์ „๊ฐœ ์˜ˆ์‹œ

template<typename... Args>
void example(Args... args) {
    // args...  โ†’ ํŒฉ ์ „๊ฐœ! ๊ฐ ์š”์†Œ๋กœ ํŽผ์ณ์ง
    // sizeof...(args) โ†’ ํŒฉ์˜ ํฌ๊ธฐ(๊ฐœ์ˆ˜) ๋ฐ˜ํ™˜
    
    std::cout << sizeof...(args) << "๊ฐœ์˜ ์ธ์ž\n";
}
๐Ÿ’ก sizeof... ์—ฐ์‚ฐ์ž: ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ฐ˜ํ™˜ํ•ด์ค˜. sizeof...(Args)๋‚˜ sizeof...(args) ๋‘˜ ๋‹ค ์‚ฌ์šฉ ๊ฐ€๋Šฅ!
ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ ์ „๊ฐœ ๊ณผ์ • ์‹œ๊ฐํ™” printAll(1, 3.14, "hello", true) Args = {int, double, const char*, bool} / args = {1, 3.14, "hello", true} ํŒฉ ์ „๊ฐœ (args...) int 1 double 3.14 const char* "hello" bool true ๊ฐ ์š”์†Œ๊ฐ€ ๋…๋ฆฝ์ ์ธ ํƒ€์ž…์œผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์ฒ˜๋ฆฌ๋จ ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ฒฐ์ • โ†’ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ ์ œ๋กœ! ๐Ÿš€ sizeof...(Args) = 4 | sizeof...(args) = 4

๐Ÿ”„ ์žฌ๊ท€๋ฅผ ์ด์šฉํ•œ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ ์ฒ˜๋ฆฌ

C++11~C++14 ์‹œ์ ˆ์—๋Š” ๊ฐ€๋ณ€ ์ธ์ž ํŒฉ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฃผ๋œ ๋ฐฉ๋ฒ•์ด ์žฌ๊ท€ ํ…œํ”Œ๋ฆฟ์ด์—ˆ์–ด. ๊ฐœ๋…์€ ์ด๋ž˜: ํŒฉ์—์„œ ์ฒซ ๋ฒˆ์งธ ์›์†Œ๋ฅผ ๋–ผ์–ด๋‚ด์„œ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋‚˜๋จธ์ง€๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฑฐ์•ผ. ๋งˆ์น˜ ์–‘ํŒŒ ๊ป์งˆ ๋ฒ—๊ธฐ๋“ฏ์ด!

์˜ˆ์ œ 1: ์žฌ๊ท€๋กœ ๋ชจ๋“  ์ธ์ž ์ถœ๋ ฅํ•˜๊ธฐ

#include <iostream>

// ๊ธฐ์ € ์ผ€์ด์Šค (์žฌ๊ท€ ์ข…๋ฃŒ ์กฐ๊ฑด)
void printAll() {
    std::cout << "\n";  // ์•„๋ฌด๊ฒƒ๋„ ์—†์œผ๋ฉด ์ค„๋ฐ”๊ฟˆ๋งŒ
}

// ์žฌ๊ท€ ์ผ€์ด์Šค
template<typename First, typename... Rest>
void printAll(First first, Rest... rest) {
    std::cout << first << " ";
    printAll(rest...);  // ๋‚˜๋จธ์ง€๋ฅผ ์žฌ๊ท€ ์ฒ˜๋ฆฌ
}

int main() {
    printAll(1, 3.14, "hello", true);
    // ์ถœ๋ ฅ: 1 3.14 hello 1
    return 0;
}

์ด ์ฝ”๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ๋‹จ๊ณ„๋ณ„๋กœ ๋ณด๋ฉด:

1
printAll(1, 3.14, "hello", true) ํ˜ธ์ถœ โ†’ First=int(1), Rest={double, const char*, bool}
2
1 ์ถœ๋ ฅ ํ›„ printAll(3.14, "hello", true) ์žฌ๊ท€ ํ˜ธ์ถœ
3
3.14 ์ถœ๋ ฅ ํ›„ printAll("hello", true) ์žฌ๊ท€ ํ˜ธ์ถœ
4
"hello" ์ถœ๋ ฅ ํ›„ printAll(true) ์žฌ๊ท€ ํ˜ธ์ถœ
5
true ์ถœ๋ ฅ ํ›„ printAll() ํ˜ธ์ถœ โ†’ ๊ธฐ์ € ์ผ€์ด์Šค ์‹คํ–‰, ์ข…๋ฃŒ!
โš ๏ธ ์ฃผ์˜! ์žฌ๊ท€ ๋ฐฉ์‹์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ธฐ์ € ์ผ€์ด์Šค(base case)๊ฐ€ ํ•„์š”ํ•ด. ์—†์œผ๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ ๋ฐœ์ƒ! ๊ธฐ์ € ์ผ€์ด์Šค๋Š” ์ธ์ž๊ฐ€ 0๊ฐœ์ผ ๋•Œ์˜ ์˜ค๋ฒ„๋กœ๋“œ์•ผ.

์˜ˆ์ œ 2: ์žฌ๊ท€๋กœ ํ•ฉ๊ณ„ ๊ตฌํ•˜๊ธฐ

// ๊ธฐ์ € ์ผ€์ด์Šค
template<typename T>
T sum(T val) {
    return val;
}

// ์žฌ๊ท€ ์ผ€์ด์Šค
template<typename First, typename... Rest>
auto sum(First first, Rest... rest) {
    return first + sum(rest...);
}

int main() {
    std::cout << sum(1, 2, 3, 4, 5) << "\n";  // 15
    std::cout << sum(1.1, 2.2, 3.3) << "\n";  // 6.6
    return 0;
}

์žฌ๊ท€ ๋ฐฉ์‹, ์ž˜ ๋™์ž‘ํ•˜๊ธด ํ•ด. ๊ทผ๋ฐ ์†”์งํžˆ ์ข€ ๋ฒˆ๊ฑฐ๋กญ์ง€ ์•Š์•„? ๊ธฐ์ € ์ผ€์ด์Šค ๋”ฐ๋กœ ์จ์•ผ ํ•˜๊ณ , ์ฝ”๋“œ๋„ ๊ธธ์–ด์ง€๊ณ ... ๊ทธ๋ž˜์„œ C++17์—์„œ ํด๋“œ ํ‘œํ˜„์‹์ด ๋“ฑ์žฅํ•œ ๊ฑฐ์•ผ! ๐ŸŽŠ


โœจ ํด๋“œ ํ‘œํ˜„์‹ (Fold Expressions) โ€” C++17์˜ ๊ฒŒ์ž„ ์ฒด์ธ์ €

ํด๋“œ ํ‘œํ˜„์‹์€ C++17์—์„œ ๋„์ž…๋œ ๊ธฐ๋Šฅ์œผ๋กœ, ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ์„ ๋‹จ ํ•œ ์ค„์˜ ํ‘œํ˜„์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ์žฌ๊ท€ ์—†์ด! ๊ธฐ์ € ์ผ€์ด์Šค ์—†์ด! ์ง„์งœ ํ˜๋ช…์ด์•ผ. ๐Ÿ˜

"ํด๋“œ(Fold)"๋ผ๋Š” ์ด๋ฆ„์€ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ fold/reduce ๊ฐœ๋…์—์„œ ์™”์–ด. ์—ฌ๋Ÿฌ ๊ฐ’์„ ํ•˜๋‚˜๋กœ "์ ‘์–ด์„œ" ํ•ฉ์น˜๋Š” ๊ฑฐ์•ผ.

ํด๋“œ ํ‘œํ˜„์‹์˜ 4๊ฐ€์ง€ ํ˜•ํƒœ

ํ˜•ํƒœ ๋ฌธ๋ฒ• ์ „๊ฐœ ๊ฒฐ๊ณผ
๋‹จํ•ญ ์šฐ์ธก ํด๋“œ (args op ...) arg1 op (arg2 op (arg3 op ...))
๋‹จํ•ญ ์ขŒ์ธก ํด๋“œ (... op args) ((arg1 op arg2) op arg3) op ...
์ดํ•ญ ์šฐ์ธก ํด๋“œ (args op ... op init) arg1 op (arg2 op (... op init))
์ดํ•ญ ์ขŒ์ธก ํด๋“œ (init op ... op args) ((init op arg1) op arg2) op ...

์ฒ˜์Œ ๋ณด๋ฉด ์ข€ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ์–ด. ํ•˜๋‚˜์”ฉ ์˜ˆ์ œ๋กœ ๋ณด์ž!

๐ŸŽฏ ๋‹จํ•ญ ํด๋“œ โ€” ๊ฐ€์žฅ ๊ธฐ๋ณธ

#include <iostream>

// ๋‹จํ•ญ ์šฐ์ธก ํด๋“œ๋กœ ํ•ฉ๊ณ„ ๊ตฌํ•˜๊ธฐ
template<typename... Args>
auto sum(Args... args) {
    return (args + ...);  // ๋‹จํ•ญ ์šฐ์ธก ํด๋“œ
    // ์ „๊ฐœ: arg1 + (arg2 + (arg3 + ...))
}

// ๋‹จํ•ญ ์ขŒ์ธก ํด๋“œ๋กœ ํ•ฉ๊ณ„ ๊ตฌํ•˜๊ธฐ
template<typename... Args>
auto sumLeft(Args... args) {
    return (... + args);  // ๋‹จํ•ญ ์ขŒ์ธก ํด๋“œ
    // ์ „๊ฐœ: ((arg1 + arg2) + arg3) + ...
}

int main() {
    std::cout << sum(1, 2, 3, 4, 5) << "\n";     // 15
    std::cout << sumLeft(1, 2, 3, 4, 5) << "\n"; // 15
    return 0;
}
๐Ÿ’ก ์šฐ์ธก vs ์ขŒ์ธก ํด๋“œ: ๋ง์…ˆ์ด๋‚˜ ๊ณฑ์…ˆ์ฒ˜๋Ÿผ ๊ฒฐํ•ฉ๋ฒ•์น™์ด ์„ฑ๋ฆฝํ•˜๋Š” ์—ฐ์‚ฐ์€ ๊ฒฐ๊ณผ๊ฐ€ ๊ฐ™์•„. ํ•˜์ง€๋งŒ ๋บ„์…ˆ์ด๋‚˜ ๋‚˜๋ˆ—์…ˆ์€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜!
์˜ˆ: (1 - 2 - 3) ์šฐ์ธก ํด๋“œ โ†’ 1 - (2 - 3) = 2, ์ขŒ์ธก ํด๋“œ โ†’ (1 - 2) - 3 = -4

๐ŸŽฏ ์ดํ•ญ ํด๋“œ โ€” ์ดˆ๊ธฐ๊ฐ’ ํฌํ•จ

// ์ดํ•ญ ์ขŒ์ธก ํด๋“œ โ€” ์ดˆ๊ธฐ๊ฐ’ 0 ํฌํ•จ
template<typename... Args>
auto sumWithInit(Args... args) {
    return (0 + ... + args);  // ์ดํ•ญ ์ขŒ์ธก ํด๋“œ
    // ์ „๊ฐœ: ((0 + arg1) + arg2) + arg3 ...
}

// ์ดํ•ญ ํด๋“œ๋กœ ์ถœ๋ ฅ (์‰ผํ‘œ ์—ฐ์‚ฐ์ž ํ™œ์šฉ)
template<typename... Args>
void printAll(Args... args) {
    (std::cout << ... << args);  // ์ดํ•ญ ์ขŒ์ธก ํด๋“œ
    std::cout << "\n";
}

int main() {
    std::cout << sumWithInit(1, 2, 3) << "\n"; // 6
    printAll(1, " ", 3.14, " ", "hello");       // 1 3.14 hello
    return 0;
}

์ดํ•ญ ํด๋“œ์—์„œ 0 + ... + args๋Š” ํŒฉ์ด ๋น„์–ด์žˆ์–ด๋„ ์•ˆ์ „ํ•ด! ๋นˆ ํŒฉ์— ๋‹จํ•ญ ํด๋“œ๋ฅผ ์“ฐ๋ฉด ์ผ๋ถ€ ์—ฐ์‚ฐ์ž๋Š” ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š”๋ฐ, ์ดํ•ญ ํด๋“œ๋Š” ์ดˆ๊ธฐ๊ฐ’์ด ์žˆ์œผ๋‹ˆ๊นŒ ๊ดœ์ฐฎ์•„. ๐Ÿ‘

ํด๋“œ ํ‘œํ˜„์‹ 4๊ฐ€์ง€ ํ˜•ํƒœ ๋น„๊ต โ‘  ๋‹จํ•ญ ์šฐ์ธก ํด๋“œ (args + ...) a + (b + (c + d)) ์˜ค๋ฅธ์ชฝ๋ถ€ํ„ฐ ์ ‘ํž˜ ์˜ˆ: (1 + ...) โ†’ 1+(2+(3+4)) = 10 โ‘ก ๋‹จํ•ญ ์ขŒ์ธก ํด๋“œ (... + args) ((a + b) + c) + d ์™ผ์ชฝ๋ถ€ํ„ฐ ์ ‘ํž˜ ์˜ˆ: (... + 1) โ†’ ((1+2)+3)+4 = 10 โ‘ข ์ดํ•ญ ์šฐ์ธก ํด๋“œ (args op ... op init) a op (b op (c op init)) ์ดˆ๊ธฐ๊ฐ’ ํฌํ•จ, ์˜ค๋ฅธ์ชฝ๋ถ€ํ„ฐ ์˜ˆ: (args + ... + 0) โ†’ a+(b+(c+0)) โ‘ฃ ์ดํ•ญ ์ขŒ์ธก ํด๋“œ (init op ... op args) ((init op a) op b) op c ์ดˆ๊ธฐ๊ฐ’ ํฌํ•จ, ์™ผ์ชฝ๋ถ€ํ„ฐ ์˜ˆ: (0 + ... + args) โ†’ ((0+a)+b)+c C++17 ์ด์ƒ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ๐ŸŽฏ

๐Ÿ› ๏ธ ์‹ค์ „ ์˜ˆ์ œ ๋ชจ์Œ โ€” ์ด๋ž˜์„œ ์“ฐ๋Š” ๊ฑฐ์•ผ!

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ดค์œผ๋‹ˆ๊นŒ ์ด์ œ ์ง„์งœ ์‹ค์ „์—์„œ ์–ด๋–ป๊ฒŒ ์“ฐ๋Š”์ง€ ๋ณด์ž. ์ด ์˜ˆ์ œ๋“ค ๋ณด๋ฉด "์•„, ์ด๋ž˜์„œ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์ด ํ•„์š”ํ•˜๊ตฌ๋‚˜!" ํ•˜๊ณ  ๋ฌด๋ฆŽ ํƒ ์น  ๊ฑฐ์•ผ. ๐Ÿ˜„

๐Ÿ”ฅ ์˜ˆ์ œ 1: ํƒ€์ž… ์•ˆ์ „ํ•œ printf ๋งŒ๋“ค๊ธฐ

#include <iostream>
#include <string>

// ํƒ€์ž… ์•ˆ์ „ํ•œ ์ถœ๋ ฅ ํ•จ์ˆ˜
template<typename... Args>
void safePrint(Args&&... args) {
    // ์ดํ•ญ ์ขŒ์ธก ํด๋“œ๋กœ ๋ชจ๋“  ์ธ์ž ์ถœ๋ ฅ
    (std::cout << ... << args);
    std::cout << "\n";
}

int main() {
    safePrint("์ด๋ฆ„: ", "ํ™๊ธธ๋™", ", ๋‚˜์ด: ", 25);
    safePrint("์›์ฃผ์œจ: ", 3.14159, ", ์ฐธ: ", true);
    safePrint(1, 2, 3, 4, 5);
    return 0;
}
// ์ถœ๋ ฅ:
// ์ด๋ฆ„: ํ™๊ธธ๋™, ๋‚˜์ด: 25
// ์›์ฃผ์œจ: 3.14159, ์ฐธ: 1
// 12345

๐Ÿ”ฅ ์˜ˆ์ œ 2: ๋ชจ๋“  ์ธ์ž๊ฐ€ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ๊ฒ€์‚ฌ

#include <iostream>

// ๋ชจ๋“  ์ธ์ž๊ฐ€ ์–‘์ˆ˜์ธ์ง€ ํ™•์ธ
template<typename... Args>
bool allPositive(Args... args) {
    return (... && (args > 0));  // ๋‹จํ•ญ ์ขŒ์ธก ํด๋“œ + ๋…ผ๋ฆฌ AND
}

// ํ•˜๋‚˜๋ผ๋„ ์–‘์ˆ˜์ธ์ง€ ํ™•์ธ
template<typename... Args>
bool anyPositive(Args... args) {
    return (... || (args > 0));  // ๋‹จํ•ญ ์ขŒ์ธก ํด๋“œ + ๋…ผ๋ฆฌ OR
}

int main() {
    std::cout << allPositive(1, 2, 3, 4) << "\n";   // 1 (true)
    std::cout << allPositive(1, -2, 3) << "\n";     // 0 (false)
    std::cout << anyPositive(-1, -2, 3) << "\n";    // 1 (true)
    std::cout << anyPositive(-1, -2, -3) << "\n";   // 0 (false)
    return 0;
}

๐Ÿ”ฅ ์˜ˆ์ œ 3: ๊ฐ€๋ณ€ ์ธ์ž๋กœ ๋ฒกํ„ฐ์— ์—ฌ๋Ÿฌ ์š”์†Œ ์ถ”๊ฐ€

#include <iostream>
#include <vector>

template<typename T, typename... Args>
void pushAll(std::vector<T>& vec, Args&&... args) {
    // ์‰ผํ‘œ ์—ฐ์‚ฐ์ž + ํด๋“œ๋กœ ์—ฌ๋Ÿฌ ์š”์†Œ ํ•œ ๋ฒˆ์— ์ถ”๊ฐ€
    (vec.push_back(std::forward<Args>(args)), ...);
}

int main() {
    std::vector<int> v;
    pushAll(v, 10, 20, 30, 40, 50);
    
    for (int x : v) {
        std::cout << x << " ";
    }
    // ์ถœ๋ ฅ: 10 20 30 40 50
    return 0;
}

๐Ÿ”ฅ ์˜ˆ์ œ 4: ์ตœ๋Œ“๊ฐ’ ๊ตฌํ•˜๊ธฐ

#include <iostream>
#include <algorithm>

// ๊ฐ€๋ณ€ ์ธ์ž๋กœ ์ตœ๋Œ“๊ฐ’ ๊ตฌํ•˜๊ธฐ
template<typename First, typename... Rest>
auto maxOf(First first, Rest... rest) {
    if constexpr (sizeof...(rest) == 0) {
        return first;
    } else {
        return std::max(first, maxOf(rest...));
    }
}

int main() {
    std::cout << maxOf(3, 1, 4, 1, 5, 9, 2, 6) << "\n"; // 9
    std::cout << maxOf(3.14, 2.71, 1.41) << "\n";       // 3.14
    return 0;
}
๐Ÿ’ก if constexpr: C++17์—์„œ ๋„์ž…๋œ ์ปดํŒŒ์ผ ํƒ€์ž„ ์กฐ๊ฑด๋ฌธ์ด์•ผ. ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ๊ณผ ์ฐฐ๋–ก๊ถํ•ฉ! ์กฐ๊ฑด์ด ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ฒฐ์ •๋˜์–ด์„œ ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๊ฐ€ ์•„์˜ˆ ์ƒ์„ฑ๋˜์ง€ ์•Š์•„.

๐Ÿ”ฅ ์˜ˆ์ œ 5: ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ฒด์ธ

#include <iostream>
#include <functional>

// ์—ฌ๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰
template<typename... Funcs>
void callAll(Funcs&&... funcs) {
    (funcs(), ...);  // ๋‹จํ•ญ ์šฐ์ธก ํด๋“œ + ํ•จ์ˆ˜ ํ˜ธ์ถœ
}

int main() {
    auto f1 = []{ std::cout << "์ฒซ ๋ฒˆ์งธ ์‹คํ–‰!\n"; };
    auto f2 = []{ std::cout << "๋‘ ๋ฒˆ์งธ ์‹คํ–‰!\n"; };
    auto f3 = []{ std::cout << "์„ธ ๋ฒˆ์งธ ์‹คํ–‰!\n"; };
    
    callAll(f1, f2, f3);
    // ์ถœ๋ ฅ:
    // ์ฒซ ๋ฒˆ์งธ ์‹คํ–‰!
    // ๋‘ ๋ฒˆ์งธ ์‹คํ–‰!
    // ์„ธ ๋ฒˆ์งธ ์‹คํ–‰!
    return 0;
}

๐ŸŽ“ ๊ณ ๊ธ‰ ํŒจํ„ด โ€” ์ง„์งœ ์‹ค๋ ฅ์ž๋“ค์ด ์“ฐ๋Š” ๋ฐฉ๋ฒ•

๊ธฐ์ดˆ๋Š” ๋‹ค ๋ดค์–ด. ์ด์ œ ์ข€ ๋” ๊ณ ๊ธ‰์Šค๋Ÿฌ์šด ํŒจํ„ด๋“ค์„ ๋ณด์ž. ์ด๋Ÿฐ ๊ฑธ ์•Œ๋ฉด ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ "์˜ค, ์ด ์‚ฌ๋žŒ C++ ์ข€ ์•„๋Š”๋ฐ?" ์†Œ๋ฆฌ ๋“ค์„ ์ˆ˜ ์žˆ์–ด. ๐Ÿ˜Ž

๐Ÿš€ ํŒจํ„ด 1: ํƒ€์ž… ์ฒดํฌ โ€” ํŠน์ • ํƒ€์ž…์ธ์ง€ ํ™•์ธ

#include <iostream>
#include <type_traits>

// ๋ชจ๋“  ์ธ์ž๊ฐ€ ์ •์ˆ˜ํ˜•์ธ์ง€ ํ™•์ธ
template<typename... Args>
constexpr bool allIntegral() {
    return (std::is_integral_v<Args> && ...);
}

// ์‚ฌ์šฉ ์˜ˆ
template<typename... Args>
auto safeSum(Args... args) {
    static_assert(allIntegral<Args...>(), 
                  "์ •์ˆ˜ํ˜• ์ธ์ž๋งŒ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค!");
    return (args + ...);
}

int main() {
    std::cout << safeSum(1, 2, 3) << "\n";  // OK: 6
    // safeSum(1, 2.0, 3);  // ์ปดํŒŒ์ผ ์—๋Ÿฌ! double์€ ์ •์ˆ˜ํ˜• ์•„๋‹˜
    return 0;
}

๐Ÿš€ ํŒจํ„ด 2: ์ธ๋ฑ์Šค ์‹œํ€€์Šค์™€ ๊ฒฐํ•ฉ

#include <iostream>
#include <tuple>
#include <utility>

// ํŠœํ”Œ์˜ ๋ชจ๋“  ์š”์†Œ ์ถœ๋ ฅ
template<typename Tuple, std::size_t... I>
void printTupleImpl(const Tuple& t, std::index_sequence<I...>) {
    // ํด๋“œ ํ‘œํ˜„์‹์œผ๋กœ ๊ฐ ์ธ๋ฑ์Šค์˜ ์š”์†Œ ์ถœ๋ ฅ
    ((std::cout << std::get<I>(t) << " "), ...);
    std::cout << "\n";
}

template<typename... Args>
void printTuple(const std::tuple<Args...>& t) {
    printTupleImpl(t, std::index_sequence_for<Args...>{});
}

int main() {
    auto t = std::make_tuple(42, 3.14, "hello", true);
    printTuple(t);  // 42 3.14 hello 1
    return 0;
}

๐Ÿš€ ํŒจํ„ด 3: ์™„๋ฒฝ ์ „๋‹ฌ(Perfect Forwarding)๊ณผ ๊ฒฐํ•ฉ

#include <iostream>
#include <memory>

// ํŒฉํ† ๋ฆฌ ํ•จ์ˆ˜ โ€” ์™„๋ฒฝ ์ „๋‹ฌ๋กœ ๊ฐ์ฒด ์ƒ์„ฑ
template<typename T, typename... Args>
std::unique_ptr<T> makeUnique(Args&&... args) {
    return std::unique_ptr<T>(
        new T(std::forward<Args>(args)...)
    );
}

struct Person {
    std::string name;
    int age;
    Person(std::string n, int a) : name(n), age(a) {}
};

int main() {
    auto p = makeUnique<Person>("ํ™๊ธธ๋™", 25);
    std::cout << p->name << ", " << p->age << "\n";
    // ํ™๊ธธ๋™, 25
    return 0;
}
๐Ÿ’ก std::forward<Args>(args)...: ์ด ํŒจํ„ด์ด ์™„๋ฒฝ ์ „๋‹ฌ + ํŒฉ ์ „๊ฐœ์˜ ์กฐํ•ฉ์ด์•ผ. std::forward<Args>(args)๊ฐ€ ๊ฐ ์›์†Œ์— ์ ์šฉ๋˜๋ฉด์„œ ํŒฉ์ด ์ „๊ฐœ๋ผ. ์‹ค์ œ๋กœ std::make_unique๋„ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ์–ด!

๐Ÿš€ ํŒจํ„ด 4: ๋นˆ ํŒฉ ์ฒ˜๋ฆฌ ์ฃผ์˜์‚ฌํ•ญ

// ๋‹จํ•ญ ํด๋“œ์—์„œ ๋นˆ ํŒฉ ํ—ˆ์šฉ ์—ฐ์‚ฐ์ž
// &&  โ†’ ๋นˆ ํŒฉ์ด๋ฉด true ๋ฐ˜ํ™˜
// ||  โ†’ ๋นˆ ํŒฉ์ด๋ฉด false ๋ฐ˜ํ™˜
// ,   โ†’ ๋นˆ ํŒฉ์ด๋ฉด void() ๋ฐ˜ํ™˜

template<typename... Args>
bool allTrue(Args... args) {
    return (... && args);  // ๋นˆ ํŒฉ์ด๋ฉด true (ํ•ญ๋“ฑ์›)
}

template<typename... Args>
bool anyTrue(Args... args) {
    return (... || args);  // ๋นˆ ํŒฉ์ด๋ฉด false (ํ•ญ๋“ฑ์›)
}

int main() {
    std::cout << allTrue() << "\n";  // 1 (true) โ€” ๋นˆ ํŒฉ OK
    std::cout << anyTrue() << "\n";  // 0 (false) โ€” ๋นˆ ํŒฉ OK
    
    // ์ฃผ์˜: + ์—ฐ์‚ฐ์ž๋Š” ๋นˆ ํŒฉ ๋‹จํ•ญ ํด๋“œ ๋ถˆ๊ฐ€!
    // auto s = (... + args);  // ๋นˆ ํŒฉ์ด๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ!
    // ํ•ด๊ฒฐ: ์ดํ•ญ ํด๋“œ ์‚ฌ์šฉ (0 + ... + args)
    return 0;
}

โšก ๊ฐ€๋ณ€ ์ธ์ž ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ

ํ•จ์ˆ˜๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ์—๋„ ๊ฐ€๋ณ€ ์ธ์ž๋ฅผ ์“ธ ์ˆ˜ ์žˆ์–ด! ๋Œ€ํ‘œ์ ์ธ ์˜ˆ๊ฐ€ std::tuple์ด์•ผ. ์ง์ ‘ ๊ฐ„๋‹จํ•œ ๋ฒ„์ „์„ ๋งŒ๋“ค์–ด๋ณด์ž.

#include <iostream>

// ๊ฐ„๋‹จํ•œ TypeList ๊ตฌํ˜„
template<typename... Types>
struct TypeList {
    static constexpr std::size_t size = sizeof...(Types);
};

// ํŠน์ • ํƒ€์ž…์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
template<typename Target, typename... Types>
struct Contains {
    static constexpr bool value = 
        (std::is_same_v<Target, Types> || ...);
};

int main() {
    using MyTypes = TypeList<int, double, std::string>;
    std::cout << MyTypes::size << "\n";  // 3
    
    constexpr bool hasInt = 
        Contains<int, double, float, int>::value;
    std::cout << hasInt << "\n";  // 1 (true)
    
    constexpr bool hasChar = 
        Contains<char, double, float, int>::value;
    std::cout << hasChar << "\n";  // 0 (false)
    return 0;
}

์ƒ์†์„ ์ด์šฉํ•œ ๋ฏน์Šค์ธ ํŒจํ„ด

// ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์„ ๋ฏน์Šค์ธ์œผ๋กœ ํ•ฉ์„ฑํ•˜๋Š” ํŒจํ„ด
struct Printable {
    void print() { std::cout << "์ถœ๋ ฅ ๊ฐ€๋Šฅ!\n"; }
};

struct Serializable {
    void serialize() { std::cout << "์ง๋ ฌํ™” ๊ฐ€๋Šฅ!\n"; }
};

struct Loggable {
    void log() { std::cout << "๋กœ๊น… ๊ฐ€๋Šฅ!\n"; }
};

// ๊ฐ€๋ณ€ ์ธ์ž ์ƒ์†์œผ๋กœ ๋ฏน์Šค์ธ ํ•ฉ์„ฑ
template<typename... Mixins>
class Component : public Mixins... {
public:
    Component() : Mixins()... {}
};

int main() {
    Component<Printable, Serializable, Loggable> comp;
    comp.print();      // ์ถœ๋ ฅ ๊ฐ€๋Šฅ!
    comp.serialize();  // ์ง๋ ฌํ™” ๊ฐ€๋Šฅ!
    comp.log();        // ๋กœ๊น… ๊ฐ€๋Šฅ!
    return 0;
}

์ด ๋ฏน์Šค์ธ ํŒจํ„ด, ์ง„์งœ ๊ฐ•๋ ฅํ•ด. ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์กฐํ•ฉํ•ด์„œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๋””์ž์ธ ํŒจํ„ด์—์„œ ๋งํ•˜๋Š” ์ปดํฌ์ง€์…˜(Composition)์„ ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ตฌํ˜„ํ•˜๋Š” ๊ฑฐ์•ผ! ๐ŸŽจ


๐Ÿ“Š ์žฌ๊ท€ vs ํด๋“œ ํ‘œํ˜„์‹ โ€” ์–ธ์ œ ๋ญ˜ ์จ์•ผ ํ•ด?

์ž, ์ด์ œ ์žฌ๊ท€ ๋ฐฉ์‹๊ณผ ํด๋“œ ํ‘œํ˜„์‹์„ ๋‹ค ๋ดค์œผ๋‹ˆ๊นŒ ๋น„๊ตํ•ด๋ณด์ž. ์–ด๋–ค ์ƒํ™ฉ์—์„œ ๋ญ˜ ์“ฐ๋Š” ๊ฒŒ ์ข‹์„๊นŒ?

ํ•ญ๋ชฉ ์žฌ๊ท€ ๋ฐฉ์‹ (C++11~) ํด๋“œ ํ‘œํ˜„์‹ (C++17~)
์ฝ”๋“œ ๊ธธ์ด ๊ธธ๋‹ค (๊ธฐ์ € ์ผ€์ด์Šค ํ•„์š”) ์งง๋‹ค (ํ•œ ์ค„)
๊ฐ€๋…์„ฑ ๋ณต์žกํ•  ์ˆ˜ ์žˆ์Œ ์ง๊ด€์ 
์ปดํŒŒ์ผ ์†๋„ ๋А๋ฆด ์ˆ˜ ์žˆ์Œ ๋น ๋ฆ„
๋ณต์žกํ•œ ๋กœ์ง ๊ตฌํ˜„ ๊ฐ€๋Šฅ ์ œํ•œ์ 
C++ ๋ฒ„์ „ C++11 ์ด์ƒ C++17 ์ด์ƒ
๋””๋ฒ„๊น… ์–ด๋ ค์›€ ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฌ์›€
๐Ÿ’ก ๊ฒฐ๋ก : C++17 ์ด์ƒ์„ ์“ธ ์ˆ˜ ์žˆ๋‹ค๋ฉด ํด๋“œ ํ‘œํ˜„์‹์„ ์šฐ์„  ์‚ฌ์šฉํ•ด. ๋‹จ์ˆœํ•œ ์—ฐ์‚ฐ(ํ•ฉ๊ณ„, ์ถœ๋ ฅ, ๋…ผ๋ฆฌ ์—ฐ์‚ฐ ๋“ฑ)์€ ํด๋“œ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋ณต์žกํ•œ ๋กœ์ง์ด ํ•„์š”ํ•  ๋•Œ๋งŒ ์žฌ๊ท€๋ฅผ ์จ. ๊ทธ๋ฆฌ๊ณ  if constexpr๊ณผ ํ•จ๊ป˜ ์“ฐ๋ฉด ์žฌ๊ท€๋„ ํ›จ์”ฌ ๊น”๋”ํ•ด์ ธ!

๐ŸŒŸ ์‹ค์ œ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ์˜ ํ™œ์šฉ

๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์€ C++ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ณณ๊ณณ์— ์ˆจ์–ด์žˆ์–ด. ์šฐ๋ฆฌ๊ฐ€ ๋งค์ผ ์“ฐ๋Š” ๊ฒƒ๋“ค์ด ์‚ฌ์‹ค ์ด ๊ธฐ์ˆ ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ฑฐ์•ผ!

๐Ÿ“š ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ ์‚ฌ์šฉ ์˜ˆ std::tuple std::make_tuple std::make_unique std::make_shared std::function std::bind std::variant std::visit std::apply std::invoke

์˜ˆ๋ฅผ ๋“ค์–ด std::make_unique<T>(args...)๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ std::forward<Args>(args)...๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์™„๋ฒฝ ์ „๋‹ฌ๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด. ์šฐ๋ฆฌ๊ฐ€ ์œ„์—์„œ ์ง์ ‘ ๊ตฌํ˜„ํ•œ ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์€ ์›๋ฆฌ์•ผ!

๋˜ํ•œ std::tuple์€ ๊ฐ€๋ณ€ ์ธ์ž ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ์˜ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ์•ผ. ์–ด๋–ค ํƒ€์ž…์ด๋“ , ๋ช‡ ๊ฐœ๋“  ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ฑฐ์ง€.

// std::apply โ€” ํŠœํ”Œ์˜ ์›์†Œ๋ฅผ ํ•จ์ˆ˜ ์ธ์ž๋กœ ์ „๋‹ฌ
#include <tuple>
#include <functional>
#include <iostream>

int add(int a, int b, int c) {
    return a + b + c;
}

int main() {
    auto args = std::make_tuple(1, 2, 3);
    int result = std::apply(add, args);
    std::cout << result << "\n";  // 6
    return 0;
}

์ด๋Ÿฐ ๊ฒƒ๋“ค์„ ์ดํ•ดํ•˜๊ณ  ๋‚˜๋ฉด, ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ C++ ๊ด€๋ จ ํ”„๋กœ์ ํŠธ๋‚˜ ๊ฐ•์˜๋ฅผ ์ฐพ์•„๋ณผ ๋•Œ๋„ ํ›จ์”ฌ ๊นŠ์ด ์žˆ๋Š” ๋‚ด์šฉ์„ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๊ฒŒ ๋ผ. ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์„ ์ดํ•ดํ•œ๋‹ค๋Š” ๊ฑด C++ ๋ฉ”ํƒ€ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋ฌธ์„ ์—ฐ ๊ฑฐ๋‚˜ ๋‹ค๋ฆ„์—†๊ฑฐ๋“ ! ๐Ÿšช


๐Ÿ› ํ”ํ•œ ์‹ค์ˆ˜์™€ ์ฃผ์˜์‚ฌํ•ญ

์ด์ œ ์‹ค์ˆ˜ํ•˜๊ธฐ ์‰ฌ์šด ๋ถ€๋ถ„๋“ค์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ. ์ด๊ฑฐ ๋ฏธ๋ฆฌ ์•Œ์•„๋‘๋ฉด ์‚ฝ์งˆ ์‹œ๊ฐ„์„ ์—„์ฒญ ์ค„์ผ ์ˆ˜ ์žˆ์–ด!

โŒ ์‹ค์ˆ˜ 1: ํŒฉ ์ „๊ฐœ ์œ„์น˜ ์˜ค๋ฅ˜

template<typename... Args>
void wrong(Args... args) {
    // โŒ ์ž˜๋ชป๋œ ์‚ฌ์šฉ โ€” ํŒฉ ์ „๊ฐœ ์—†์ด ํŒฉ ์‚ฌ์šฉ
    // std::cout << args;  // ์—๋Ÿฌ!
    
    // โœ… ์˜ฌ๋ฐ”๋ฅธ ์‚ฌ์šฉ โ€” ํด๋“œ๋กœ ์ „๊ฐœ
    (std::cout << ... << args);
}

โŒ ์‹ค์ˆ˜ 2: ๋นˆ ํŒฉ์— ๋‹จํ•ญ ํด๋“œ ์‚ฌ์šฉ

template<typename... Args>
auto badSum(Args... args) {
    // โŒ ๋นˆ ํŒฉ์ด๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ!
    return (args + ...);
}

template<typename... Args>
auto goodSum(Args... args) {
    // โœ… ์ดํ•ญ ํด๋“œ๋กœ ์ดˆ๊ธฐ๊ฐ’ ์ œ๊ณต
    return (0 + ... + args);
}

// badSum()  โ†’ ์ปดํŒŒ์ผ ์—๋Ÿฌ
// goodSum() โ†’ 0 ๋ฐ˜ํ™˜ (OK)

โŒ ์‹ค์ˆ˜ 3: ์žฌ๊ท€ ๊ธฐ์ € ์ผ€์ด์Šค ๋ˆ„๋ฝ

// โŒ ๊ธฐ์ € ์ผ€์ด์Šค ์—†์Œ โ€” ์ปดํŒŒ์ผ ์—๋Ÿฌ!
template<typename First, typename... Rest>
void printBad(First first, Rest... rest) {
    std::cout << first << " ";
    printBad(rest...);  // Rest๊ฐ€ ๋น„๋ฉด ์–ด๋–ป๊ฒŒ?? ์—๋Ÿฌ!
}

// โœ… ๊ธฐ์ € ์ผ€์ด์Šค ์ถ”๊ฐ€
void printGood() {}  // ๊ธฐ์ € ์ผ€์ด์Šค

template<typename First, typename... Rest>
void printGood(First first, Rest... rest) {
    std::cout << first << " ";
    printGood(rest...);
}

โŒ ์‹ค์ˆ˜ 4: ํด๋“œ ํ‘œํ˜„์‹ ๊ด„ํ˜ธ ๋ˆ„๋ฝ

template<typename... Args>
auto sum(Args... args) {
    // โŒ ๊ด„ํ˜ธ ์—†์œผ๋ฉด ์ปดํŒŒ์ผ ์—๋Ÿฌ!
    // return args + ...;
    
    // โœ… ๋ฐ˜๋“œ์‹œ ๊ด„ํ˜ธ๋กœ ๊ฐ์‹ธ์•ผ ํ•จ!
    return (args + ...);
}
โš ๏ธ ํด๋“œ ํ‘œํ˜„์‹์€ ๋ฐ˜๋“œ์‹œ ๊ด„ํ˜ธ๋กœ ๊ฐ์‹ธ์•ผ ํ•ด! (args + ...)์ฒ˜๋Ÿผ. ๊ด„ํ˜ธ ์—†์œผ๋ฉด ๋ฌธ๋ฒ• ์—๋Ÿฌ์•ผ.

๐ŸŽฏ ์ข…ํ•ฉ ์‹ค์ „ ์˜ˆ์ œ โ€” ๋ฏธ๋‹ˆ ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ

๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์„ ํ™œ์šฉํ•œ ์‹ค์šฉ์ ์ธ ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ค„๊ฒŒ. ๊ฐ„๋‹จํ•œ ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ์ด์•ผ. ์ด๋Ÿฐ ํŒจํ„ด์€ ๊ฒŒ์ž„ ์—”์ง„์ด๋‚˜ GUI ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ž์ฃผ ์“ฐ์—ฌ!

#include <iostream>
#include <vector>
#include <functional>

// ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ์œผ๋กœ ๋งŒ๋“  ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ
template<typename... Args>
class Event {
public:
    using Handler = std::function<void(Args...)>;
    
    // ํ•ธ๋“ค๋Ÿฌ ๋“ฑ๋ก
    void subscribe(Handler handler) {
        handlers_.push_back(std::move(handler));
    }
    
    // ์ด๋ฒคํŠธ ๋ฐœ์ƒ โ€” ๋ชจ๋“  ํ•ธ๋“ค๋Ÿฌ์— ์ธ์ž ์ „๋‹ฌ
    void emit(Args... args) {
        for (auto& handler : handlers_) {
            handler(args...);
        }
    }
    
private:
    std::vector<Handler> handlers_;
};

int main() {
    // ์ •์ˆ˜ ํ•˜๋‚˜๋ฅผ ๋ฐ›๋Š” ์ด๋ฒคํŠธ
    Event<int> onScoreChanged;
    
    onScoreChanged.subscribe([](int score) {
        std::cout << "์ ์ˆ˜ ๋ณ€๊ฒฝ: " << score << "\n";
    });
    onScoreChanged.subscribe([](int score) {
        if (score >= 100) std::cout << "๐Ÿ† ์ตœ๊ณ  ์ ์ˆ˜!\n";
    });
    
    onScoreChanged.emit(50);   // ์ ์ˆ˜ ๋ณ€๊ฒฝ: 50
    onScoreChanged.emit(100);  // ์ ์ˆ˜ ๋ณ€๊ฒฝ: 100 + ๐Ÿ† ์ตœ๊ณ  ์ ์ˆ˜!
    
    // ๋ฌธ์ž์—ด๊ณผ ์ •์ˆ˜๋ฅผ ๋ฐ›๋Š” ์ด๋ฒคํŠธ
    Event<std::string, int> onPlayerAction;
    
    onPlayerAction.subscribe([](std::string action, int value) {
        std::cout << "ํ”Œ๋ ˆ์ด์–ด ํ–‰๋™: " << action 
                  << " (๊ฐ’: " << value << ")\n";
    });
    
    onPlayerAction.emit("์ ํ”„", 5);
    onPlayerAction.emit("๊ณต๊ฒฉ", 30);
    
    return 0;
}
// ์ถœ๋ ฅ:
// ์ ์ˆ˜ ๋ณ€๊ฒฝ: 50
// ์ ์ˆ˜ ๋ณ€๊ฒฝ: 100
// ๐Ÿ† ์ตœ๊ณ  ์ ์ˆ˜!
// ํ”Œ๋ ˆ์ด์–ด ํ–‰๋™: ์ ํ”„ (๊ฐ’: 5)
// ํ”Œ๋ ˆ์ด์–ด ํ–‰๋™: ๊ณต๊ฒฉ (๊ฐ’: 30)

์ด ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ, ์–ด๋•Œ? Event<int>, Event<string, int> ์ฒ˜๋Ÿผ ์›ํ•˜๋Š” ํƒ€์ž… ์กฐํ•ฉ์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ ๋•๋ถ„์— ํƒ€์ž… ์•ˆ์ „ํ•˜๊ฒŒ! ์ด๋Ÿฐ ํŒจํ„ด์„ ์ดํ•ดํ•˜๊ณ  ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ C++ ๊ด€๋ จ ํ”„๋ฆฌ๋žœ์„œ ํ™œ๋™์„ ํ•  ๋•Œ๋„ ํ›จ์”ฌ ๊ฒฝ์Ÿ๋ ฅ์ด ์ƒ๊ธธ ๊ฑฐ์•ผ. ๐Ÿ’ผ


๐Ÿ ๋งˆ๋ฌด๋ฆฌ โ€” ํ•ต์‹ฌ ์ •๋ฆฌ

์ž, ์˜ค๋Š˜ ์—„์ฒญ ๋งŽ์€ ๊ฑธ ๋ฐฐ์› ์–ด. ๋จธ๋ฆฟ์†์ด ์ข€ ๋ณต์žกํ•  ์ˆ˜๋„ ์žˆ์œผ๋‹ˆ๊นŒ ํ•ต์‹ฌ๋งŒ ๋”ฑ ์ •๋ฆฌํ•ด์ค„๊ฒŒ!

๐Ÿ“Œ ๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ ํ•ต์‹ฌ ์š”์•ฝ
1
ํŒŒ๋ผ๋ฏธํ„ฐ ํŒฉ: typename... Args๋กœ ์„ ์–ธ, 0๊ฐœ ์ด์ƒ์˜ ํƒ€์ž…/๊ฐ’์„ ๋ฌถ์Œ
2
ํŒฉ ์ „๊ฐœ: args...๋กœ ํŒฉ์„ ํŽผ์นจ, ๋‹ค์–‘ํ•œ ์ปจํ…์ŠคํŠธ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
3
sizeof...: ํŒฉ์˜ ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋ฐ˜ํ™˜
4
์žฌ๊ท€ ๋ฐฉ์‹: C++11~, ๊ธฐ์ € ์ผ€์ด์Šค ํ•„์ˆ˜, ๋ณต์žกํ•œ ๋กœ์ง ๊ตฌํ˜„ ๊ฐ€๋Šฅ
5
ํด๋“œ ํ‘œํ˜„์‹: C++17~, ๋‹จ ํ•œ ์ค„๋กœ ํŒฉ ์ฒ˜๋ฆฌ, 4๊ฐ€์ง€ ํ˜•ํƒœ ์กด์žฌ
6
if constexpr: C++17~, ์ปดํŒŒ์ผ ํƒ€์ž„ ์กฐ๊ฑด ๋ถ„๊ธฐ, ์žฌ๊ท€์™€ ์ฐฐ๋–ก๊ถํ•ฉ
๐ŸŽฏ ์ตœ์ข… ์กฐ์–ธ: ์ฒ˜์Œ์—” ํด๋“œ ํ‘œํ˜„์‹์ด ๋‚ฏ์„ค์–ด ๋ณด์—ฌ๋„, ๋ช‡ ๋ฒˆ ์จ๋ณด๋ฉด ๊ธˆ๋ฐฉ ์ต์ˆ™ํ•ด์ ธ. ํŠนํžˆ (args + ...), (std::cout << ... << args), (func(args), ...) ์ด ์„ธ ๊ฐ€์ง€ ํŒจํ„ด๋งŒ ์™ธ์›Œ๋„ ์ผ์ƒ์ ์ธ ์ฝ”๋”ฉ์—์„œ ์—„์ฒญ ์œ ์šฉํ•˜๊ฒŒ ์“ธ ์ˆ˜ ์žˆ์–ด!

C++17 ์ด์ƒ ํ™˜๊ฒฝ์ด๋ผ๋ฉด ํด๋“œ ํ‘œํ˜„์‹์„ ์ ๊ทน ํ™œ์šฉํ•˜๊ณ , ๋ณต์žกํ•œ ๋กœ์ง์ด ํ•„์š”ํ•  ๋•Œ๋Š” if constexpr๊ณผ ํ•จ๊ป˜ ์žฌ๊ท€๋ฅผ ์จ. ๊ทธ๋ฆฌ๊ณ  ํ•ญ์ƒ ๋นˆ ํŒฉ ์ฒ˜๋ฆฌ๋ฅผ ๊ณ ๋ คํ•˜๋Š” ์Šต๊ด€์„ ๋“ค์—ฌ!

๊ฐ€๋ณ€ ์ธ์ž ํ…œํ”Œ๋ฆฟ๊ณผ ํด๋“œ ํ‘œํ˜„์‹์€ C++์˜ ์ง„์งœ ํŒŒ์›Œ๋ฅผ ๋А๋‚„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด์•ผ. ์ฒ˜์Œ์—” ์–ด๋ ต๊ฒŒ ๋А๊ปด์ง€์ง€๋งŒ, ์ดํ•ดํ•˜๊ณ  ๋‚˜๋ฉด ์ฝ”๋“œ๊ฐ€ ์–ผ๋งˆ๋‚˜ ์šฐ์•„ํ•˜๊ณ  ๊ฐ•๋ ฅํ•ด์ง€๋Š”์ง€ ์‹ค๊ฐํ•  ๊ฑฐ์•ผ. ์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ ๊ผญ ์ง์ ‘ ์ฝ”๋”ฉํ•ด๋ณด๋ฉด์„œ ์ตํ˜€๋ด! ๐Ÿ’ช๐Ÿ”ฅ

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.