Ver3.5 ๐ฏ ๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ๊ณผ ํด๋ ํํ์ โ C++ ๋ง๋ฒ์ฌ๊ฐ ๋๋ ๊ฐ์ฅ ๋น ๋ฅธ ๊ธธ

๐ฏ ๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ๊ณผ ํด๋ ํํ์ โ C++ ๋ง๋ฒ์ฌ๊ฐ ๋๋ ๊ฐ์ฅ ๋น ๋ฅธ ๊ธธ
Variadic Templates & Fold Expressions๋ฅผ ์น๊ตฌ์ฒ๋ผ ์ฝ๊ณ ์ฌ๋ฏธ์๊ฒ ํํค์ณ๋ณด์! ๐
์ผ, ์์งํ ๋งํด๋ณผ๊ฒ. C++ ๊ณต๋ถํ๋ค๊ฐ ๊ฐ๋ณ ์ธ์ ํ
ํ๋ฆฟ(Variadic Templates)์ด๋ผ๋ ๋จ์ด ์ฒ์ ๋ดค์ ๋ ์ด๋ค ๋๋์ด์์ด? ๐
"์ด๊ฒ ๋ญ ์๋ฆฌ์ผ..." ํ๊ณ ์ฐฝ ๋ซ๊ณ ์ถ์์ง? ๋๋ ๊ทธ๋ฌ์ด. ๊ทผ๋ฐ ํ ๋ฒ ์ ๋๋ก ์ดํดํ๊ณ ๋๋ฉด ์ง์ง ์ด๊ฑฐ ์์ด ์ด๋ป๊ฒ ์ฝ๋ฉํ๋ ์ถ์ ์ ๋๋ก ๊ฐ๋ ฅํ ๋๊ตฌ์ผ.
์ค๋์ ๊ฐ๋ณ ์ธ์ ํ
ํ๋ฆฟ๊ณผ C++17์์ ๋ฑ์ฅํ ํด๋ ํํ์(Fold Expressions)์ ์์ ํ ๋ฏ์ด๋ณผ ๊ฑฐ์ผ. ์ฝ๋ ์์ ๋นต๋นตํ๊ฒ ๋ฃ๊ณ , ๊ฐ๋
๋ ์ฝ๊ฒ ํ์ด์ค ํ
๋๊น ๋๊น์ง ๋ฐ๋ผ์๋ด! ๐ช
๐ค ๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ์ด ์ ํ์ํด?
๋จผ์ ๋ฐฐ๊ฒฝ๋ถํฐ ์ดํดํด๋ณด์. ์๋ C ์ธ์ด ์์ ์๋ ๊ฐ๋ณ ์ธ์ ํจ์๊ฐ ์์์ด. printf ๊ฐ์ ๊ฑฐ ๋ง์ด์ผ. ๊ทผ๋ฐ ๊ทธ๊ฑด ํ์
์์ ์ฑ์ด ์ ํ ์์์ด. ์๋ชป๋ ํ์
๋๊ธฐ๋ฉด ๋ฐํ์์ ํฐ์ง๊ฑฐ๋ ์ด์ํ ๊ฐ ๋์ค๊ณ ... ์ง์ง ์ง๋ขฐ๋ฐญ์ด์์ง.
#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...(Args)๋ sizeof...(args) ๋ ๋ค ์ฌ์ฉ ๊ฐ๋ฅ!
๐ ์ฌ๊ท๋ฅผ ์ด์ฉํ ๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ ์ฒ๋ฆฌ
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;
}
์ด ์ฝ๋๊ฐ ์ด๋ป๊ฒ ๋์ํ๋์ง ๋จ๊ณ๋ณ๋ก ๋ณด๋ฉด:
printAll(1, 3.14, "hello", true) ํธ์ถ โ First=int(1), Rest={double, const char*, bool}1 ์ถ๋ ฅ ํ printAll(3.14, "hello", true) ์ฌ๊ท ํธ์ถ3.14 ์ถ๋ ฅ ํ printAll("hello", true) ์ฌ๊ท ํธ์ถ"hello" ์ถ๋ ฅ ํ printAll(true) ์ฌ๊ท ํธ์ถtrue ์ถ๋ ฅ ํ printAll() ํธ์ถ โ ๊ธฐ์ ์ผ์ด์ค ์คํ, ์ข
๋ฃ!์์ 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;
}
์:
(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๋ ํฉ์ด ๋น์ด์์ด๋ ์์ ํด! ๋น ํฉ์ ๋จํญ ํด๋๋ฅผ ์ฐ๋ฉด ์ผ๋ถ ์ฐ์ฐ์๋ ์๋ฌ๊ฐ ๋๋๋ฐ, ์ดํญ ํด๋๋ ์ด๊ธฐ๊ฐ์ด ์์ผ๋๊น ๊ด์ฐฎ์. ๐
๐ ๏ธ ์ค์ ์์ ๋ชจ์ โ ์ด๋์ ์ฐ๋ ๊ฑฐ์ผ!
์ด๋ก ์ ์ถฉ๋ถํ ๋ดค์ผ๋๊น ์ด์ ์ง์ง ์ค์ ์์ ์ด๋ป๊ฒ ์ฐ๋์ง ๋ณด์. ์ด ์์ ๋ค ๋ณด๋ฉด "์, ์ด๋์ ๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ์ด ํ์ํ๊ตฌ๋!" ํ๊ณ ๋ฌด๋ฆ ํ ์น ๊ฑฐ์ผ. ๐
๐ฅ ์์ 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;
}
๐ฅ ์์ 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::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 ์ด์ |
| ๋๋ฒ๊น | ์ด๋ ค์ | ์๋์ ์ผ๋ก ์ฌ์ |
if constexpr๊ณผ ํจ๊ป ์ฐ๋ฉด ์ฌ๊ท๋ ํจ์ฌ ๊น๋ํด์ ธ!
๐ ์ค์ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์์ ํ์ฉ
๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ์ C++ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณณ๊ณณ์ ์จ์ด์์ด. ์ฐ๋ฆฌ๊ฐ ๋งค์ผ ์ฐ๋ ๊ฒ๋ค์ด ์ฌ์ค ์ด ๊ธฐ์ ๋ก ๋ง๋ค์ด์ง ๊ฑฐ์ผ!
์๋ฅผ ๋ค์ด 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++ ๊ด๋ จ ํ๋ฆฌ๋์ ํ๋์ ํ ๋๋ ํจ์ฌ ๊ฒฝ์๋ ฅ์ด ์๊ธธ ๊ฑฐ์ผ. ๐ผ
๐ ๋ง๋ฌด๋ฆฌ โ ํต์ฌ ์ ๋ฆฌ
์, ์ค๋ ์์ฒญ ๋ง์ ๊ฑธ ๋ฐฐ์ ์ด. ๋จธ๋ฆฟ์์ด ์ข ๋ณต์กํ ์๋ ์์ผ๋๊น ํต์ฌ๋ง ๋ฑ ์ ๋ฆฌํด์ค๊ฒ!
typename... Args๋ก ์ ์ธ, 0๊ฐ ์ด์์ ํ์
/๊ฐ์ ๋ฌถ์args...๋ก ํฉ์ ํผ์นจ, ๋ค์ํ ์ปจํ
์คํธ์์ ์ฌ์ฉ ๊ฐ๋ฅ(args + ...), (std::cout << ... << args), (func(args), ...) ์ด ์ธ ๊ฐ์ง ํจํด๋ง ์ธ์๋ ์ผ์์ ์ธ ์ฝ๋ฉ์์ ์์ฒญ ์ ์ฉํ๊ฒ ์ธ ์ ์์ด!C++17 ์ด์ ํ๊ฒฝ์ด๋ผ๋ฉด ํด๋ ํํ์์ ์ ๊ทน ํ์ฉํ๊ณ , ๋ณต์กํ ๋ก์ง์ด ํ์ํ ๋๋ if constexpr๊ณผ ํจ๊ป ์ฌ๊ท๋ฅผ ์จ. ๊ทธ๋ฆฌ๊ณ ํญ์ ๋น ํฉ ์ฒ๋ฆฌ๋ฅผ ๊ณ ๋ คํ๋ ์ต๊ด์ ๋ค์ฌ!
๊ฐ๋ณ ์ธ์ ํ ํ๋ฆฟ๊ณผ ํด๋ ํํ์์ C++์ ์ง์ง ํ์๋ฅผ ๋๋ ์ ์๋ ๊ธฐ๋ฅ์ด์ผ. ์ฒ์์ ์ด๋ ต๊ฒ ๋๊ปด์ง์ง๋ง, ์ดํดํ๊ณ ๋๋ฉด ์ฝ๋๊ฐ ์ผ๋ง๋ ์ฐ์ํ๊ณ ๊ฐ๋ ฅํด์ง๋์ง ์ค๊ฐํ ๊ฑฐ์ผ. ์ค๋ ๋ฐฐ์ด ๋ด์ฉ ๊ผญ ์ง์ ์ฝ๋ฉํด๋ณด๋ฉด์ ์ตํ๋ด! ๐ช๐ฅ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.