๐Ÿš€ ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•œ ์ •์  ์–ด์„ค์…˜: C++์˜ ๋งˆ๋ฒ• ๊ฐ™์€ ๊ธฐ๋Šฅ! ๐ŸŽฉ

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•œ ์ •์  ์–ด์„ค์…˜: C++์˜ ๋งˆ๋ฒ• ๊ฐ™์€ ๊ธฐ๋Šฅ! ๐ŸŽฉ

 

 

์•ˆ๋…•ํ•˜์„ธ์š”, ์ฝ”๋”ฉ ๋งˆ๋ฒ•์‚ฌ ์—ฌ๋Ÿฌ๋ถ„! ์˜ค๋Š˜์€ C++์˜ ํฅ๋ฏธ์ง„์ง„ํ•œ ์„ธ๊ณ„๋กœ ์—ฌ๋Ÿฌ๋ถ„์„ ์ดˆ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ 'ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•œ ์ •์  ์–ด์„ค์…˜'์ด๋ผ๋Š” ๊ฐ•๋ ฅํ•œ ๋งˆ๋ฒ• ์ฃผ๋ฌธ์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ์ด ์ฃผ๋ฌธ์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ๋”์šฑ ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ค„ ๊ฑฐ์˜ˆ์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์‹ค๋ ฅ์„ ํ•œ ๋‹จ๊ณ„ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๐Ÿ˜‰

๐Ÿ’ก ์•Œ๊ณ  ๊ณ„์…จ๋‚˜์š”? ํƒ€์ž… ํŠน์„ฑ(Type Traits)์€ C++11๋ถ€ํ„ฐ ๋„์ž…๋œ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์œผ๋กœ, ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ํƒ€์ž…์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์–ป๊ฑฐ๋‚˜ ํƒ€์ž…์„ ๋ณ€ํ˜•ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋ฅผ ์ด์šฉํ•œ ์ •์  ์–ด์„ค์…˜์€ ์ฝ”๋“œ์˜ ์•ˆ์ •์„ฑ์„ ํฌ๊ฒŒ ๋†’์—ฌ์ค๋‹ˆ๋‹ค!

๐Ÿง™โ€โ™‚๏ธ ํƒ€์ž… ํŠน์„ฑ: ์ฝ”๋“œ์˜ ์•ˆ์ „ ์ง€ํ‚ด์ด

ํƒ€์ž… ํŠน์„ฑ์€ ๋งˆ์น˜ ์ฝ”๋“œ์˜ ์•ˆ์ „ ์ง€ํ‚ด์ด์™€ ๊ฐ™์•„์š”. ์—ฌ๋Ÿฌ๋ถ„์ด ์˜๋„ํ•œ ๋Œ€๋กœ ์ฝ”๋“œ๊ฐ€ ์ž‘๋™ํ•˜๋Š”์ง€ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ํ™•์ธํ•ด์ฃผ์ฃ . ์ด๋Š” ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ „๋ฌธ๊ฐ€๋“ค์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฒ€ํ† ํ•ด์ฃผ๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ์žก์•„๋‚ด๊ณ , ๋” ๋‚˜์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๊ฑฐ์ฃ ! ๐Ÿ›ก๏ธ

๐Ÿ” ํƒ€์ž… ํŠน์„ฑ์˜ ๊ธฐ๋ณธ ๊ฐœ๋…

ํƒ€์ž… ํŠน์„ฑ์€ <type_traits> ํ—ค๋”์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์€ ํ…œํ”Œ๋ฆฟ ๋ฉ”ํƒ€ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ž…์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๊ฑฐ๋‚˜, ํƒ€์ž…์„ ๋ณ€ํ˜•ํ•ฉ๋‹ˆ๋‹ค.

  • โœ… std::is_integral: ์ •์ˆ˜ ํƒ€์ž…์ธ์ง€ ํ™•์ธ
  • โœ… std::is_floating_point: ๋ถ€๋™์†Œ์ˆ˜์  ํƒ€์ž…์ธ์ง€ ํ™•์ธ
  • โœ… std::is_array: ๋ฐฐ์—ด์ธ์ง€ ํ™•์ธ
  • โœ… std::is_pointer: ํฌ์ธํ„ฐ์ธ์ง€ ํ™•์ธ
  • โœ… std::remove_reference: ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•œ ํƒ€์ž… ์–ป๊ธฐ

์ด๋Ÿฐ ํƒ€์ž… ํŠน์„ฑ๋“ค์„ ์ด์šฉํ•˜๋ฉด, ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ํƒ€์ž…์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ๊ฒ€์‚ฌ์™€ ๋ณ€ํ˜•์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์ฝ”๋“œ์— ๋งˆ๋ฒ•์˜ ๋‹๋ณด๊ธฐ๋ฅผ ๋“ค์ด๋Œ€๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ ! ๐Ÿ”ฎ

๐Ÿ› ๏ธ ์ •์  ์–ด์„ค์…˜: ์ปดํŒŒ์ผ ์‹œ๊ฐ„์˜ ๋งˆ๋ฒ•

์ •์  ์–ด์„ค์…˜์€ static_assert๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ์กฐ๊ฑด์„ ๊ฒ€์‚ฌํ•˜๊ณ , ์กฐ๊ฑด์ด ๊ฑฐ์ง“์ด๋ฉด ์ปดํŒŒ์ผ์„ ์ค‘๋‹จ์‹œํ‚ค๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์˜ˆ์š”.


template <typename T>
void processNumber(T value) {
    static_assert(std::is_arithmetic<T>::value, "Arithmetic type expected");
    // ํ•จ์ˆ˜ ๋‚ด์šฉ...
}
  

์ด ์ฝ”๋“œ๋Š” processNumber ํ•จ์ˆ˜์— ์‚ฐ์ˆ  ํƒ€์ž…(์ •์ˆ˜ ๋˜๋Š” ๋ถ€๋™์†Œ์ˆ˜์ )๋งŒ ์ „๋‹ฌ๋˜๋„๋ก ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํƒ€์ž…์ด ์ „๋‹ฌ๋˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์นœ์ ˆํ•˜๊ฒŒ ๊ฒฝ๊ณ ๋ฅผ ํ•ด์ฃผ์ฃ . ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ „๋ฌธ๊ฐ€๊ฐ€ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฅผ ๋ฆฌ๋ทฐํ•ด์ฃผ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ์š”! ๐Ÿ‘จโ€๐Ÿ’ป

๐ŸŒŸ ํŒ: ์ •์  ์–ด์„ค์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ์‹œ๊ฐ„ ์˜ค๋ฅ˜๋กœ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋Š” ๋ฒ„๊ทธ๋ฅผ ๋” ๋นจ๋ฆฌ, ๋” ์‰ฝ๊ฒŒ ์žก์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค!

๐ŸŽญ ํƒ€์ž… ํŠน์„ฑ์˜ ๋‹ค์–‘ํ•œ ์–ผ๊ตด๋“ค

ํƒ€์ž… ํŠน์„ฑ์€ ์ •๋ง ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์ „๋ฌธ๊ฐ€๋“ค์„ ๋งŒ๋‚  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๋ช‡ ๊ฐ€์ง€ ์žฌ๋ฏธ์žˆ๋Š” ์˜ˆ๋ฅผ ์‚ดํŽด๋ณผ๊นŒ์š”?

๐Ÿ”ข ํƒ€์ž… ๋ณ€ํ™˜์˜ ๋งˆ๋ฒ•

std::conditional์„ ์‚ฌ์šฉํ•˜๋ฉด ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฑด ๋งˆ์น˜ ๋งˆ๋ฒ•์‚ฌ๊ฐ€ ์ฃผ๋ฌธ์„ ์™ธ์›Œ ๋ฌผ๊ฑด์„ ๋ณ€ํ˜•์‹œํ‚ค๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ด์š”!


template <bool Condition, typename T, typename F>
struct magical_type_selector {
    using type = typename std::conditional<Condition, T, F>::type;
};

// ์‚ฌ์šฉ ์˜ˆ
using result = magical_type_selector<true, int, float>::type; // int ์„ ํƒ
using another_result = magical_type_selector<false, int, float>::type; // float ์„ ํƒ
  

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฝ”๋“œ๊ฐ€ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋˜‘๋˜‘ํ•˜๊ฒŒ ์ ์‘ํ•˜๋Š” ๊ฑฐ์ฃ ! ๐Ÿง 

๐Ÿ” ํƒ€์ž… ์ •๋ณด ํƒ์ •

std::is_same์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‘ ํƒ€์ž…์ด ๊ฐ™์€์ง€ ๋น„๊ตํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฑด ๋งˆ์น˜ ๋‘ ๋งˆ๋ฒ• ๋ฌผ์•ฝ์ด ๊ฐ™์€ ํšจ๊ณผ๋ฅผ ๋‚ด๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜์ฃ !


template <typename T, typename U>
void compare_types() {
    if (std::is_same<T, U>::value) {
        std::cout << "๋‘ ํƒ€์ž…์€ ๊ฐ™์•„์š”!" << std::endl;
    } else {
        std::cout << "๋‘ ํƒ€์ž…์€ ๋‹ฌ๋ผ์š”!" << std::endl;
    }
}

// ์‚ฌ์šฉ ์˜ˆ
compare_types<int, int>(); // "๋‘ ํƒ€์ž…์€ ๊ฐ™์•„์š”!" ์ถœ๋ ฅ
compare_types<int, float>(); // "๋‘ ํƒ€์ž…์€ ๋‹ฌ๋ผ์š”!" ์ถœ๋ ฅ
  

์ด๋Ÿฐ ์‹์œผ๋กœ ํƒ€์ž…์„ ๋น„๊ตํ•˜๋ฉด, ์ฝ”๋“œ์˜ ๋™์ž‘์„ ๋” ์ •ํ™•ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ์— ๊ผญ ๋งž๋Š” ์ „๋ฌธ๊ฐ€๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์ฃ ! ๐Ÿ•ต๏ธโ€โ™‚๏ธ

๐Ÿ’ก ์žฌ๋ฏธ์žˆ๋Š” ์‚ฌ์‹ค: ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๋ณต์žกํ•œ ๊ณ„์‚ฐ๋„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์š”! ์˜ˆ๋ฅผ ๋“ค์–ด, ํŒฉํ† ๋ฆฌ์–ผ ๊ฐ™์€ ์ˆ˜ํ•™ ์—ฐ์‚ฐ์„ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค. ์ด๊ฑด ์ •๋ง ๋งˆ๋ฒ• ๊ฐ™์€ ์ผ์ด์ฃ !

๐ŸŽญ ์ •์  ์–ด์„ค์…˜์˜ ์‹ค์ „ ์‘์šฉ

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

๐Ÿ›ก๏ธ ์•ˆ์ „ํ•œ ํ•จ์ˆ˜ ํ…œํ”Œ๋ฆฟ ๋งŒ๋“ค๊ธฐ

ํ•จ์ˆ˜ ํ…œํ”Œ๋ฆฟ์„ ์ž‘์„ฑํ•  ๋•Œ, ํŠน์ • ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ํƒ€์ž…๋งŒ ๋ฐ›๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์ฃ . ์ด๋Ÿด ๋•Œ ์ •์  ์–ด์„ค์…˜์ด ํฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.


template <typename T>
void safeDelete(T* ptr) {
    static_assert(std::is_object<T>::value, "T must be an object type");
    static_assert(!std::is_array<T>::value, "Array types are not allowed");
    delete ptr;
}

// ์‚ฌ์šฉ ์˜ˆ
int* intPtr = new int(10);
safeDelete(intPtr); // OK

int arr[] = {1, 2, 3};
// safeDelete(arr); // ์ปดํŒŒ์ผ ์˜ค๋ฅ˜! ๋ฐฐ์—ด์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  

์ด safeDelete ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด ํƒ€์ž…์˜ ํฌ์ธํ„ฐ๋งŒ ๋ฐ›์•„๋“ค์ด๊ณ , ๋ฐฐ์—ด์€ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด delete[]๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๋ฐฐ์—ด์„ ์‹ค์ˆ˜๋กœ deleteํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ „๋ฌธ๊ฐ€์˜ ์กฐ์–ธ์„ ๋ฐ›์•„ ์‹ค์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ๋ฐฉ์ง€ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ ! ๐Ÿ›ก๏ธ

๐Ÿ‹๏ธโ€โ™€๏ธ ์ตœ์ ํ™”๋œ ํ•จ์ˆ˜ ์˜ค๋ฒ„๋กœ๋”ฉ

๋•Œ๋กœ๋Š” ํƒ€์ž…์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์–ด์š”. ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ์ด๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


// ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ
template <typename T>
typename std::enable_if<!std::is_integral<T>::value, void>::type
process(T value) {
    std::cout << "์ผ๋ฐ˜ ์ฒ˜๋ฆฌ: " << value << std::endl;
}

// ์ •์ˆ˜ ํƒ€์ž…์ธ ๊ฒฝ์šฐ
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
process(T value) {
    std::cout << "์ •์ˆ˜ ์ฒ˜๋ฆฌ: " << value * 2 << std::endl;
}

// ์‚ฌ์šฉ ์˜ˆ
process(3.14); // ์ถœ๋ ฅ: ์ผ๋ฐ˜ ์ฒ˜๋ฆฌ: 3.14
process(42);   // ์ถœ๋ ฅ: ์ •์ˆ˜ ์ฒ˜๋ฆฌ: 84
  

์ด ์˜ˆ์ œ์—์„œ๋Š” std::enable_if๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์ˆ˜ ํƒ€์ž…๊ณผ ๊ทธ ์™ธ์˜ ํƒ€์ž…์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๊ฐ ๋ถ„์•ผ์˜ ์ „๋ฌธ๊ฐ€๋“ค์ด ์ž์‹ ์˜ ์ „๋ฌธ ์˜์—ญ์— ๋งž๋Š” ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ด์š”! ๐ŸŽฏ

โš ๏ธ ์ฃผ์˜: ํ…œํ”Œ๋ฆฟ ๋ฉ”ํƒ€ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ๊ณผ๋„ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ํ•ด์น  ์ˆ˜ ์žˆ์–ด์š”. ํ•ญ์ƒ ๊ท ํ˜•์„ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

๐ŸŽจ ํƒ€์ž… ํŠน์„ฑ์˜ ์˜ˆ์ˆ ์  ํ™œ์šฉ

์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๋Š” ํƒ€์ž… ํŠน์„ฑ๊ณผ ์ •์  ์–ด์„ค์…˜์˜ ๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•์„ ์‚ดํŽด๋ดค์–ด์š”. ํ•˜์ง€๋งŒ ์ด ๋„๊ตฌ๋“ค์€ ๋‹จ์ˆœํžˆ ํƒ€์ž… ์ฒดํฌ๋ฅผ ๋„˜์–ด์„œ ์ •๋ง ์ฐฝ์˜์ ์ธ ๋ฐฉ์‹์œผ๋กœ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์žฌ๋Šฅ์„ ๊ฐ€์ง„ ์‚ฌ๋žŒ๋“ค์ด ๋ชจ์—ฌ ์ƒˆ๋กœ์šด ์ž‘ํ’ˆ์„ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์—์š”! ๐ŸŽญ

๐Ÿงฉ ์ปดํŒŒ์ผ ์‹œ๊ฐ„ ํƒ€์ž… ํผ์ฆ

ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๋ณต์žกํ•œ ํƒ€์ž… ํผ์ฆ์„ ํ’€ ์ˆ˜ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ฃผ์–ด์ง„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ํƒ€์ž…์„ ์„ ํƒํ•˜๋Š” ๋ฉ”ํƒ€ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”?


template <typename T, typename U, typename V>
struct choose_type {
    using type = typename std::conditional<
        std::is_same<T, U>::value,
        V,
        typename std::conditional<
            std::is_same<T, V>::value,
            U,
            T
        >::type
    >::type;
};

// ์‚ฌ์šฉ ์˜ˆ
using result1 = choose_type<int, int, float>::type; // float
using result2 = choose_type<int, float, int>::type; // float
using result3 = choose_type<int, float, double>::type; // int
  

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

๐Ÿ”ฎ ๋ฏธ๋ž˜๋ฅผ ์˜ˆ์ธกํ•˜๋Š” ์ฝ”๋“œ

ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ๋ฏธ๋ž˜์˜ C++ ํ‘œ์ค€์—์„œ ์ œ๊ณตํ•  ๊ธฐ๋Šฅ์„ ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด๋ณผ ์ˆ˜๋„ ์žˆ์–ด์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, C++20์—์„œ ๋„์ž…๋œ std::remove_cvref๋ฅผ C++17์—์„œ ๊ตฌํ˜„ํ•ด๋ณผ๊นŒ์š”?


template <typename T>
struct remove_cvref {
    using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};

template <typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

// ์‚ฌ์šฉ ์˜ˆ
static_assert(std::is_same<remove_cvref_t<const int&>, int>::value, "Should be int");
static_assert(std::is_same<remove_cvref_t<volatile int&&>, int>::value, "Should be int");
  

์ด๋ ‡๊ฒŒ ๊ตฌํ˜„ํ•œ remove_cvref๋Š” ์ฐธ์กฐ์™€ const/volatile ํ•œ์ •์ž๋ฅผ ๋ชจ๋‘ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์‹์œผ๋กœ ๋ฏธ๋ž˜์˜ ๊ธฐ๋Šฅ์„ ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด๋ณด๋ฉด, ์ฝ”๋“œ์˜ ํ˜ธํ™˜์„ฑ์„ ๋†’์ด๊ณ  ์ƒˆ๋กœ์šด ํ‘œ์ค€์œผ๋กœ์˜ ์ „ํ™˜์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋ฏธ๋ž˜์˜ ํŠธ๋ Œ๋“œ๋ฅผ ์˜ˆ์ธกํ•˜๊ณ  ์ค€๋น„ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ ! ๐Ÿ”ฎโœจ

๐Ÿ’ก ๊ฟ€ํŒ: ์ƒˆ๋กœ์šด C++ ํ‘œ์ค€์ด ๋‚˜์˜ฌ ๋•Œ๋งˆ๋‹ค ํƒ€์ž… ํŠน์„ฑ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ดํŽด๋ณด์„ธ์š”. ์ข…์ข… ๋งค์šฐ ์œ ์šฉํ•˜๊ณ  ํฅ๋ฏธ๋กœ์šด ์ƒˆ๋กœ์šด ๋„๊ตฌ๋“ค์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค!

๐Ÿ—๏ธ ์•ˆ์ „ํ•œ ์ฝ”๋“œ ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„ํ•˜๊ธฐ

ํƒ€์ž… ํŠน์„ฑ๊ณผ ์ •์  ์–ด์„ค์…˜์„ ํ™œ์šฉํ•˜๋ฉด ๋” ์•ˆ์ „ํ•˜๊ณ  ๊ฒฌ๊ณ ํ•œ ์ฝ”๋“œ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋Š” ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ์ „๋ฌธ๊ฐ€๋“ค์˜ ์กฐ์–ธ์„ ์ข…ํ•ฉํ•ด ์™„๋ฒฝํ•œ ํ”„๋กœ์ ํŠธ ๊ณ„ํš์„ ์„ธ์šฐ๋Š” ๊ฒƒ๊ณผ ๊ฐ™๋‹ต๋‹ˆ๋‹ค! ๐Ÿ‘ทโ€โ™€๏ธ๐Ÿ—๏ธ

๐Ÿ› ๏ธ ํƒ€์ž… ์•ˆ์ „ํ•œ ํŒฉํ† ๋ฆฌ ํŒจํ„ด

ํŒฉํ† ๋ฆฌ ํŒจํ„ด์€ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์บก์Šํ™”ํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด์ด์—์š”. ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ์ด ํŒจํ„ด์„ ๋”์šฑ ์•ˆ์ „ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


class Animal { public: virtual ~Animal() = default; };
class Dog : public Animal {};
class Cat : public Animal {};

template <typename T>
class AnimalFactory {
    static_assert(std::is_base_of<Animal, T>::value, "T must be derived from Animal");
public:
    static std::unique_ptr<Animal> create() {
        return std::make_unique<T>();
    }
};

// ์‚ฌ์šฉ ์˜ˆ
auto dog = AnimalFactory<Dog>::create();
auto cat = AnimalFactory<Cat>::create();
// auto invalid = AnimalFactory<int>::create(); // ์ปดํŒŒ์ผ ์˜ค๋ฅ˜!
  

์ด ์˜ˆ์ œ์—์„œ AnimalFactory๋Š” Animal์˜ ํŒŒ์ƒ ํด๋ž˜์Šค๋งŒ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ž˜๋ชป๋œ ํƒ€์ž…์˜ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์žฌ๋Šฅ๋„ท์—์„œ ๊ฐ ๋ถ„์•ผ์˜ ์ „๋ฌธ๊ฐ€๋งŒ์ด ํ•ด๋‹น ๋ถ„์•ผ์˜ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜์ฃ ! ๐Ÿพ

๐Ÿงฌ ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•œ ์ •์ฑ… ๊ธฐ๋ฐ˜ ์„ค๊ณ„

์ •์ฑ… ๊ธฐ๋ฐ˜ ์„ค๊ณ„๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์„ธ๋ถ€ ๊ตฌํ˜„์„ ์ •์ฑ… ํด๋ž˜์Šค๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ธฐ๋ฒ•์ด์—์š”. ํƒ€์ž… ํŠน์„ฑ์„ ์ด์šฉํ•˜๋ฉด ์ด๋ฅผ ๋”์šฑ ์œ ์—ฐํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


// ๋กœ๊น… ์ •์ฑ…
struct ConsoleLogging {
    static void log(const std::string& message) {
        std::cout << "Console: " << message << std::endl;
    }
};

struct FileLogging {
    static void log(const std::string& message) {
        // ํŒŒ์ผ์— ๋กœ๊ทธ ์ž‘์„ฑ (๊ฐ„๋‹จํžˆ ํ‘œํ˜„)
        std::cout << "File: " << message << std::endl;
    }
};

// ๋กœ๊ฑฐ ํด๋ž˜์Šค
template <typename LogPolicy>
class Logger {
    static_assert(std::is_class<LogPolicy>::value, "LogPolicy must be a class");
public:
    static void log(const std::string& message) {
        LogPolicy::log(message);
    }
};

// ์‚ฌ์šฉ ์˜ˆ
Logger<ConsoleLogging>::log("Hello, Console!");
Logger<FileLogging>::log("Hello, File!");
  

์ด ์˜ˆ์ œ์—์„œ๋Š” ๋กœ๊น… ๋ฐฉ์‹์„ ์ •์ฑ…์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ , Logger ํด๋ž˜์Šค๊ฐ€ ์ด ์ •์ฑ…์„ ํ…œํ”Œ๋ฆฟ ์ธ์ž๋กœ ๋ฐ›์•„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. static_assert๋ฅผ ํ†ตํ•ด LogPolicy๊ฐ€ ํด๋ž˜์Šค ํƒ€์ž…์ธ์ง€ ํ™•์ธํ•˜์—ฌ ์•ˆ์ „์„ฑ์„ ๋†’์˜€์–ด์š”. ์ด๋Š” ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ์ „๋ฌธ๊ฐ€๋“ค์˜ ์„œ๋น„์Šค๋ฅผ ์กฐํ•ฉํ•ด ๋งž์ถคํ˜• ์†”๋ฃจ์…˜์„ ๋งŒ๋“œ๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ต๋‹ˆ๋‹ค! ๐Ÿงฉโœจ

๐ŸŒŸ ์‹ฌํ™” ํŒ: SFINAE(Substitution Failure Is Not An Error) ๊ธฐ๋ฒ•๊ณผ ํƒ€์ž… ํŠน์„ฑ์„ ๊ฒฐํ•ฉํ•˜๋ฉด ๋”์šฑ ๊ฐ•๋ ฅํ•œ ํ…œํ”Œ๋ฆฟ ๋ฉ”ํƒ€ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅํ•ด์š”. ์ด๋ฅผ ํ†ตํ•ด ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ๋ณต์žกํ•œ ํƒ€์ž… ์„ ํƒ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค!

๐Ÿš€ ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•: ํƒ€์ž… ํŠน์„ฑ์˜ ์˜ˆ์ˆ 

์ž, ์ด์ œ ์šฐ๋ฆฌ๋Š” ํƒ€์ž… ํŠน์„ฑ๊ณผ ์ •์  ์–ด์„ค์…˜์˜ ๊ธฐ๋ณธ์„ ๋งˆ์Šคํ„ฐํ–ˆ์–ด์š”. ํ•˜์ง€๋งŒ ์ด ๋„๊ตฌ๋“ค์˜ ์ง„์ •ํ•œ ํž˜์€ ๋” ๊นŠ์€ ๊ณณ์— ์žˆ๋‹ต๋‹ˆ๋‹ค. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์ดˆ๋ณด์ž์—์„œ ์ „๋ฌธ๊ฐ€๋กœ ์„ฑ์žฅํ•˜๋Š” ๊ณผ์ •์ฒ˜๋Ÿผ, ์šฐ๋ฆฌ๋„ ์ด์ œ ๋” ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•์œผ๋กœ ๋‚˜์•„๊ฐ€๋ณผ๊นŒ์š”? ๐ŸŽ“โœจ

๐Ÿง™โ€โ™‚๏ธ ํƒ€์ž… ๋ฆฌ์ŠคํŠธ์™€ ๋ฉ”ํƒ€ํ•จ์ˆ˜

ํƒ€์ž… ๋ฆฌ์ŠคํŠธ๋Š” ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ํƒ€์ž…๋“ค์˜ ์‹œํ€€์Šค๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์˜ˆ์š”. ์ด๋ฅผ ์ด์šฉํ•ด ๋ณต์žกํ•œ ๋ฉ”ํƒ€ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


// ํƒ€์ž… ๋ฆฌ์ŠคํŠธ
template <typename... Ts>
struct TypeList {};

// ํƒ€์ž… ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด๋ฅผ ๊ตฌํ•˜๋Š” ๋ฉ”ํƒ€ํ•จ์ˆ˜
template <typename List>
struct Length;

template <typename... Ts>
struct Length<TypeList<Ts...>> : std::integral_constant<std::size_t, sizeof...(Ts)> {};

// n๋ฒˆ์งธ ํƒ€์ž…์„ ์–ป๋Š” ๋ฉ”ํƒ€ํ•จ์ˆ˜
template <std::size_t N, typename List>
struct NthType;

template <std::size_t N, typename T, typename... Ts>
struct NthType<N, TypeList<T, Ts...>> : NthType<N-1, TypeList<Ts...>> {};

template <typename T, typename... Ts>
struct NthType<0, TypeList<T, Ts...>> {
    using type = T;
};

// ์‚ฌ์šฉ ์˜ˆ
using MyList = TypeList<int, float, double, char>;
static_assert(Length<MyList>::value == 4, "Length should be 4");
static_assert(std::is_same<NthType<2, MyList>::type, double>::value, "3rd type should be double");
  

์ด ์˜ˆ์ œ์—์„œ๋Š” ํƒ€์ž… ๋ฆฌ์ŠคํŠธ๋ฅผ ์ •์˜ํ•˜๊ณ , ๊ทธ ๊ธธ์ด๋ฅผ ๊ตฌํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์œ„์น˜์˜ ํƒ€์ž…์„ ์–ป๋Š” ๋ฉ”ํƒ€ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ–ˆ์–ด์š”. ์ด๋Ÿฐ ๊ธฐ๋ฒ•์€ ๋ณต์žกํ•œ ํ…œํ”Œ๋ฆฟ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ ์ „๋ฌธ๊ฐ€์˜ ๊ธฐ์ˆ ์„ ์กฐํ•ฉํ•ด ์ƒˆ๋กœ์šด ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ฃ ! ๐Ÿง™โ€โ™‚๏ธ๐Ÿ”ฎ

๐Ÿ—๏ธ CRTP์™€ ํƒ€์ž… ํŠน์„ฑ์˜ ๊ฒฐํ•ฉ

CRTP(Curiously Recurring Template Pattern)๋Š” ์ •์  ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋ฒ•์ด์—์š”. ์ด๋ฅผ ํƒ€์ž… ํŠน์„ฑ๊ณผ ๊ฒฐํ•ฉํ•˜๋ฉด ๋”์šฑ ์œ ์—ฐํ•˜๊ณ  ์•ˆ์ „ํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


template <typename Derived>
class Base {
public:
    void interface() {
        static_assert(std::is_base_of<Base<Derived>, Derived>::value,
                      "Derived must inherit from Base");
        static_cast<Derived*>(this)->implementation();
    }

protected:
    ~Base() = default;
};

class Derived : public Base<Derived> {
public:
    void implementation() {
        std::cout << "Derived implementation" << std::endl;
    }
};

// ์‚ฌ์šฉ ์˜ˆ
Derived d;
d.interface(); // ์ถœ๋ ฅ: Derived implementation
  

์ด ์˜ˆ์ œ์—์„œ Base ํด๋ž˜์Šค๋Š” CRTP๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Derived ํด๋ž˜์Šค์˜ implementation( ) ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. static_assert๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Derived๊ฐ€ ์‹ค์ œ๋กœ Base๋ฅผ ์ƒ์†๋ฐ›์•˜๋Š”์ง€ ํ™•์ธํ•˜์—ฌ ์•ˆ์ „์„ฑ์„ ๋†’์˜€์–ด์š”. ์ด๋Š” ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ๋ฉ˜ํ† ์™€ ๋ฉ˜ํ‹ฐ ๊ด€๊ณ„๋ฅผ ์„ค์ •ํ•  ๋•Œ, ์ ์ ˆํ•œ ์ž๊ฒฉ์„ ๊ฐ–์ถ˜ ์‚ฌ๋žŒ๋“ค๋งŒ ์—ฐ๊ฒฐ๋˜๋„๋ก ํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•˜๋‹ต๋‹ˆ๋‹ค! ๐Ÿ‘ฅ๐Ÿ”—

๐Ÿ’ก ํ”„๋กœ ํŒ: CRTP๋Š” ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด, ์„ฑ๋Šฅ ๋ฉด์—์„œ ์ด์ ์ด ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์— ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ์„ ์ฆ๊ฐ€์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽญ ์‹ค์ „ ์‘์šฉ: ํƒ€์ž… ํŠน์„ฑ์˜ ๋งˆ๋ฒ• ์‹œ์ „ํ•˜๊ธฐ

์ž, ์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๋ชจ๋“  ๊ฒƒ์„ ์ข…ํ•ฉํ•ด์„œ ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณผ๊นŒ์š”? ์ด๋Š” ๋งˆ์น˜ ์žฌ๋Šฅ๋„ท์—์„œ ์—ฌ๋Ÿฌ๋ถ„์ด ๋ฐฐ์šด ๊ธฐ์ˆ ์„ ์‹ค์ œ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์•„์š”! ๐ŸŽจโœจ

๐Ÿงช ์•ˆ์ „ํ•œ ๋‹ค์ฐจ์› ๋ฐฐ์—ด ๋ž˜ํผ

๋‹ค์ฐจ์› ๋ฐฐ์—ด์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ๋ž˜ํผ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ด…์‹œ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ์ฐจ์› ์ˆ˜๋ฅผ ํ™•์ธํ•˜๊ณ , ์ž˜๋ชป๋œ ์ ‘๊ทผ์„ ๋ฐฉ์ง€ํ•  ๊ฑฐ์˜ˆ์š”.