๐Ÿš€ ์ปดํŒŒ์ผ ํƒ€์ž„ ๋‹คํ˜•์„ฑ: CRTP ํŒจํ„ด ์™„์ „ ์ •๋ณต! ๐Ÿš€

์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ ์ปดํŒŒ์ผ ํƒ€์ž„ ๋‹คํ˜•์„ฑ: CRTP ํŒจํ„ด ์™„์ „ ์ •๋ณต! ๐Ÿš€

 

 

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

๊ทธ๋Ÿฐ๋ฐ ์ž ๊น, ํ˜น์‹œ ์ง€๊ธˆ "์–ด? ์ด๊ฒŒ ๋ญ์ง€? ๋„ˆ๋ฌด ์–ด๋ ค์›Œ ๋ณด์ด๋Š”๋ฐ..." ํ•˜๊ณ  ๊ฒ๋จน์€ ๋ถ„ ๊ณ„์‹ ๊ฐ€์š”? ๊ฑฑ์ • ๋งˆ์„ธ์š”! ์ œ๊ฐ€ ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”. ๋งˆ์น˜ ์นดํ†ก์œผ๋กœ ์นœ๊ตฌ์™€ ๋Œ€ํ™”ํ•˜๋“ฏ์ด ํŽธํ•˜๊ฒŒ ์ฝ์–ด์ฃผ์„ธ์š”. ใ…‹ใ…‹ใ…‹

์ž, ๊ทธ๋Ÿผ ์ด์ œ๋ถ€ํ„ฐ CRTP์˜ ์„ธ๊ณ„๋กœ ๋น ์ ธ๋ณผ๊นŒ์š”? ๐ŸŠโ€โ™‚๏ธ ๋ฌผ๋ก  ์ค‘๊ฐ„์ค‘๊ฐ„ ์žฌ๋Šฅ๋„ท์—์„œ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” C++ ๊ฟ€ํŒ๋“ค๋„ ์Šฌ์ฉ์Šฌ์ฉ ์•Œ๋ ค๋“œ๋ฆด ํ…Œ๋‹ˆ ๊ท€ ๊ธฐ์šธ์—ฌ์ฃผ์„ธ์š”!

๐Ÿค” CRTP๊ฐ€ ๋ญ๊ธธ๋ž˜? ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ฐจ๊ทผ์ฐจ๊ทผ!

CRTP... ์ด๋ฆ„๋ถ€ํ„ฐ ์ข€ ๋ฌด์„œ์›Œ ๋ณด์ด์ฃ ? ใ…‹ใ…‹ใ…‹ ๊ฑฑ์ • ๋งˆ์„ธ์š”. ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณด๋ฉด ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต์ง€ ์•Š์•„์š”!

CRTP๋Š” 'Curiously Recurring Template Pattern'์˜ ์•ฝ์ž์˜ˆ์š”. ํ•œ๊ตญ์–ด๋กœ ํ•˜๋ฉด '๊ธฐ๋ฌ˜ํ•˜๊ฒŒ ๋ฐ˜๋ณต๋˜๋Š” ํ…œํ”Œ๋ฆฟ ํŒจํ„ด' ์ •๋„๊ฐ€ ๋˜๊ฒ ๋„ค์š”. ์ด๋ฆ„๋ถ€ํ„ฐ ์ข€ ์ด์ƒํ•˜์ฃ ? ๐Ÿ˜…

์ด ํŒจํ„ด์€ C++์—์„œ ์•„์ฃผ ํŠน๋ณ„ํ•œ ๊ธฐ๋ฒ•์ธ๋ฐ์š”, ์ปดํŒŒ์ผ ํƒ€์ž„์— ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋งˆ๋ฒ• ๊ฐ™์€ ๋…€์„์ด์—์š”. ๋ญ” ์†Œ๋ฆฌ๋ƒ๊ณ ์š”? ์ฐจ๊ทผ์ฐจ๊ทผ ์„ค๋ช…ํ•ด๋“œ๋ฆด๊ฒŒ์š”!

๐Ÿ” CRTP์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด:

  • ๊ธฐ๋ณธ ํด๋ž˜์Šค๊ฐ€ ์ž์‹ ์„ ์ƒ์†๋ฐ›๋Š” ํŒŒ์ƒ ํด๋ž˜์Šค๋ฅผ ํ…œํ”Œ๋ฆฟ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„์š”.
  • ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ๋ณธ ํด๋ž˜์Šค์—์„œ ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๋ฉค๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์ปดํŒŒ์ผ ํƒ€์ž„์— ๊ฒฐ์ •๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์—†์–ด์š”!

์–ด๋–ค๊ฐ€์š”? ์•„์ง๋„ ์ข€ ์ถ”์ƒ์ ์œผ๋กœ ๋Š๊ปด์ง€๋‚˜์š”? ๊ทธ๋Ÿผ ์šฐ๋ฆฌ ์ผ์ƒ์ƒํ™œ์—์„œ ๋น„์œ ๋ฅผ ๋“ค์–ด๋ณผ๊ฒŒ์š”.

CRTP๋Š” ๋งˆ์น˜... ๐Ÿค” ์Œ... ํƒ€์ž„๋จธ์‹ ์„ ํƒ€๊ณ  ๋ฏธ๋ž˜์˜ ์ž์‹ ์„ ๋งŒ๋‚˜๋Ÿฌ ๊ฐ€๋Š” ๊ฒƒ๊ณผ ๋น„์Šทํ•ด์š”! ํ˜„์žฌ์˜ ๋‹น์‹ (๊ธฐ๋ณธ ํด๋ž˜์Šค)์ด ๋ฏธ๋ž˜์˜ ๋‹น์‹ (ํŒŒ์ƒ ํด๋ž˜์Šค)์„ ์•Œ๊ณ  ์žˆ๋Š” ๊ฑฐ์ฃ . ์‹ ๊ธฐํ•˜์ง€ ์•Š๋‚˜์š”? ใ…‹ใ…‹ใ…‹

์ด๋Ÿฐ ๊ฐœ๋…์„ ์ดํ•ดํ•˜๊ณ  ๋‚˜๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์˜ C++ ์ฝ”๋”ฉ ์‹ค๋ ฅ์€ ํ•œ ๋‹จ๊ณ„ ์—…๊ทธ๋ ˆ์ด๋“œ๋  ๊ฑฐ์˜ˆ์š”. ์žฌ๋Šฅ๋„ท์—์„œ๋„ ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์„ ๋‹ค๋ฃจ๋Š” ๊ฐ•์˜๊ฐ€ ์žˆ๋‹ค๋˜๋ฐ... ํ•œ๋ฒˆ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”! ๐Ÿ˜‰

CRTP ๊ฐœ๋…๋„ ๊ธฐ๋ณธ ํด๋ž˜์Šค ํŒŒ์ƒ ํด๋ž˜์Šค

์œ„์˜ ๊ทธ๋ฆผ์„ ๋ณด์„ธ์š”. ๊ธฐ๋ณธ ํด๋ž˜์Šค๊ฐ€ ํŒŒ์ƒ ํด๋ž˜์Šค๋ฅผ "์•Œ๊ณ  ์žˆ๋Š”" ๋ชจ์Šต์ด ๋ณด์ด์‹œ๋‚˜์š”? ์ด๊ฒŒ ๋ฐ”๋กœ CRTP์˜ ํ•ต์‹ฌ์ด์—์š”!

์ž, ์ด์ œ ๊ธฐ๋ณธ ๊ฐœ๋…์€ ์žก์•˜์œผ๋‹ˆ ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณผ๊นŒ์š”? ๋‹ค์Œ ์„น์…˜์—์„œ๋Š” CRTP์˜ ์‹ค์ œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's go! ๐Ÿš€

๐Ÿ› ๏ธ CRTP ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•ด๋ณด๊ธฐ

์ž, ์ด์ œ ์‹ค์ œ๋กœ CRTP๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณผ ์ฐจ๋ก€์˜ˆ์š”. ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด์„œ ์„ค๋ช…ํ•  ํ…Œ๋‹ˆ ๊ฒ๋จน์ง€ ๋งˆ์‹œ๊ณ  ๋”ฐ๋ผ์™€ ์ฃผ์„ธ์š”! ใ…Žใ…Ž

๋จผ์ €, CRTP์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ํ•œ๋ฒˆ ๋ณผ๊นŒ์š”?


template <typename Derived>
class Base {
    // ๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ ๊ตฌํ˜„
};

class Derived : public Base<Derived> {
    // ํŒŒ์ƒ ํด๋ž˜์Šค์˜ ๊ตฌํ˜„
};

์–ด๋–ค๊ฐ€์š”? ์ข€ ์ด์ƒํ•ด ๋ณด์ด์ฃ ? ใ…‹ใ…‹ใ…‹ ๊ธฐ๋ณธ ํด๋ž˜์Šค๊ฐ€ ์ž๊ธฐ๋ฅผ ์ƒ์†๋ฐ›์„ ํด๋ž˜์Šค๋ฅผ ๋ฏธ๋ฆฌ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์€ ์ด ๊ตฌ์กฐ, ๋ฐ”๋กœ CRTP์˜ ํ•ต์‹ฌ์ด์—์š”!

์ด์ œ ์ด ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•ด์„œ ์‹ค์ œ๋กœ ์œ ์šฉํ•œ ๋ญ”๊ฐ€๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐ์ฒด ์นด์šดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”?


template <typename Derived>
class ObjectCounter {
private:
    static int count;

public:
    ObjectCounter() { ++count; }
    ~ObjectCounter() { --count; }
    static int getCount() { return count; }
};

template <typename Derived>
int ObjectCounter<Derived>::count = 0;

class MyClass : public ObjectCounter<MyClass> {
    // MyClass์˜ ๊ตฌํ˜„
};

class YourClass : public ObjectCounter<YourClass> {
    // YourClass์˜ ๊ตฌํ˜„
};

์šฐ์™€! ์ด๊ฒŒ ๋ญ”๊ฐ€ ์‹ถ์ฃ ? ใ…‹ใ…‹ใ…‹ ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณผ๊ฒŒ์š”.

๐Ÿ” ์ฝ”๋“œ ํ•ด์„ค:

  • ObjectCounter ํด๋ž˜์Šค๋Š” ํ…œํ”Œ๋ฆฟ ํด๋ž˜์Šค์˜ˆ์š”. Derived๋ผ๋Š” ํƒ€์ž…์„ ๋ฐ›์•„์š”.
  • ๊ฐ ํŒŒ์ƒ ํด๋ž˜์Šค๋งˆ๋‹ค ๋ณ„๋„์˜ count ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋ผ์š”.
  • ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ๋งˆ๋‹ค count๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ , ์†Œ๋ฉธ๋  ๋•Œ๋งˆ๋‹ค ๊ฐ์†Œํ•ด์š”.
  • MyClass์™€ YourClass๋Š” ๊ฐ๊ฐ ObjectCounter๋ฅผ ์ƒ์†๋ฐ›์•„์š”.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด MyClass์™€ YourClass์˜ ๊ฐ์ฒด ์ˆ˜๋ฅผ ๊ฐ๊ฐ ๋”ฐ๋กœ ์…€ ์ˆ˜ ์žˆ์–ด์š”. ์‹ ๊ธฐํ•˜์ง€ ์•Š๋‚˜์š”? ๐Ÿ˜ฒ

์‚ฌ์šฉ ์˜ˆ์‹œ๋ฅผ ํ•œ๋ฒˆ ๋ณผ๊นŒ์š”?


int main() {
    MyClass obj1, obj2, obj3;
    YourClass obj4, obj5;

    std::cout << "MyClass ๊ฐ์ฒด ์ˆ˜: " << MyClass::getCount() << std::endl;
    std::cout << "YourClass ๊ฐ์ฒด ์ˆ˜: " << YourClass::getCount() << std::endl;

    return 0;
}

์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด MyClass ๊ฐ์ฒด ์ˆ˜๋Š” 3, YourClass ๊ฐ์ฒด ์ˆ˜๋Š” 2๊ฐ€ ์ถœ๋ ฅ๋  ๊ฑฐ์˜ˆ์š”. ์™„์ „ ์ฉ๋‹ค! ๐Ÿ‘

์ด๋ ‡๊ฒŒ CRTP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ ์ค‘๋ณต ์—†์ด ๊ฐ ํด๋ž˜์Šค๋ณ„๋กœ ๊ฐ์ฒด ์ˆ˜๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ์„ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ๊น”๋”ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ ์–ด๋ ค์› ์„ ๊ฑฐ์˜ˆ์š”.

์žฌ๋Šฅ๋„ท์—์„œ C++ ๊ณ ๊ธ‰ ๊ณผ์ •์„ ๋“ค์–ด๋ณธ ๋ถ„๋“ค์ด๋ผ๋ฉด ์ด๋Ÿฐ ํŒจํ„ด์ด ์™œ ์œ ์šฉํ•œ์ง€ ๋ฐ”๋กœ ์ดํ•ดํ•˜์‹ค ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”. ์•„์ง ์•ˆ ๋“ค์–ด๋ณด์…จ๋‹ค๊ณ ์š”? ๊ทธ๋Ÿผ ํ•œ๋ฒˆ ์ฐพ์•„๋ณด๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”? ใ…Žใ…Ž

CRTP๋ฅผ ์ด์šฉํ•œ ๊ฐ์ฒด ์นด์šดํ„ฐ ๊ตฌ์กฐ ObjectCounter<T> count: int getCount(): int MyClass YourClass

์œ„ ๊ทธ๋ฆผ์„ ๋ณด์„ธ์š”. ObjectCounter๊ฐ€ ์–ด๋–ป๊ฒŒ MyClass์™€ YourClass์— ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š”์ง€ ํ•œ๋ˆˆ์— ๋ณด์ด์‹œ์ฃ ? ์ด๊ฒŒ ๋ฐ”๋กœ CRTP์˜ ๋งค๋ ฅ์ด์—์š”! ๐Ÿ˜

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ CRTP์˜ ๊ธฐ๋ณธ ๊ตฌํ˜„๊ณผ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ดค์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? ์ƒ๊ฐ๋ณด๋‹ค ์–ด๋ ต์ง€ ์•Š์ฃ ? ใ…Žใ…Ž

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” CRTP์˜ ๋” ๋‹ค์–‘ํ•œ ํ™œ์šฉ ์‚ฌ๋ก€๋“ค์„ ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? Let's keep going! ๐Ÿš€

๐ŸŒŸ CRTP์˜ ๋‹ค์–‘ํ•œ ํ™œ์šฉ ์‚ฌ๋ก€

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

1. ์ •์  ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„ํ•˜๊ธฐ

CRTP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€์ƒ ํ•จ์ˆ˜ ์—†์ด๋„ ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋ƒ๊ณ ์š”? ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณผ๊ฒŒ์š”!


template <typename Derived>
class Animal {
public:
    void makeSound() {
        static_cast<Derived*>(this)->sound();
    }
};

class Dog : public Animal<Dog> {
public:
    void sound() {
        std::cout << "๋ฉ๋ฉ!" << std::endl;
    }
};

class Cat : public Animal<Cat> {
public:
    void sound() {
        std::cout << "์•ผ์˜น~" << std::endl;
    }
};

์ด ์ฝ”๋“œ์—์„œ Animal ํด๋ž˜์Šค๋Š” makeSound() ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋งŒ, ์‹ค์ œ ์†Œ๋ฆฌ๋ฅผ ๋‚ด๋Š” ๊ฑด ํŒŒ์ƒ ํด๋ž˜์Šค์˜ sound() ํ•จ์ˆ˜์˜ˆ์š”. CRTP๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์˜ฌ๋ฐ”๋ฅธ sound() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฑฐ์ฃ .

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๋‹ˆ๊นŒ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๋„ ์—†๊ณ , ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋” ๋งŽ์€ ์ตœ์ ํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์™„์ „ ๊ฐœ์ด๋“! ๐Ÿ‘

2. ๋ฏน์Šค์ธ(Mixin) ๊ตฌํ˜„ํ•˜๊ธฐ

CRTP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ํด๋ž˜์Šค์— ๊ณตํ†ต ๊ธฐ๋Šฅ์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๋Ÿฐ ๊ธฐ๋ฒ•์„ '๋ฏน์Šค์ธ'์ด๋ผ๊ณ  ํ•ด์š”. ์ผ€์ดํฌ์— ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ํ† ํ•‘์„ ์–น๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ํด๋ž˜์Šค์— ๊ธฐ๋Šฅ์„ '๋ฏน์Šค์ธ'ํ•˜๋Š” ๊ฑฐ์ฃ ! ใ…‹ใ…‹ใ…‹


template <typename Derived>
class Printable {
public:
    void print() const {
        static_cast<const Derived*>(this)->doPrint();
    }
};

class Person : public Printable<Person> {
public:
    void doPrint() const {
        std::cout << "I'm a person!" << std::endl;
    }
};

class Car : public Printable<Car> {
public:
    void doPrint() const {
        std::cout << "I'm a car!" << std::endl;
    }
};

์ด ์˜ˆ์ œ์—์„œ Printable ํด๋ž˜์Šค๋Š” print() ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” ๋ฏน์Šค์ธ์ด์—์š”. Person๊ณผ Car ํด๋ž˜์Šค๋Š” ์ด ๊ธฐ๋Šฅ์„ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ฃ . ์™„์ „ ํŽธ๋ฆฌํ•˜์ง€ ์•Š๋‚˜์š”? ๐Ÿ˜„

3. ์ •์  ๋‹คํ˜•์„ฑ ๊ตฌํ˜„ํ•˜๊ธฐ

CRTP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋Ÿฐํƒ€์ž„ ๋‹คํ˜•์„ฑ ๋Œ€์‹  ์ปดํŒŒ์ผ ํƒ€์ž„ ๋‹คํ˜•์„ฑ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ด๊ฒŒ ๋ญ๊ฐ€ ์ข‹๋ƒ๊ณ ์š”? ์„ฑ๋Šฅ์ด ๋” ์ข‹์•„์ง€์ฃ !


template <typename Derived>
class Shape {
public:
    double area() const {
        return static_cast<const Derived*>(this)->computeArea();
    }
};

class Circle : public Shape<Circle> {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double computeArea() const {
        return 3.14 * radius * radius;
    }
};

class Rectangle : public Shape<Rectangle> {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double computeArea() const {
        return width * height;
    }
};

์ด ์˜ˆ์ œ์—์„œ Shape ํด๋ž˜์Šค๋Š” area() ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, ์‹ค์ œ ๋ฉด์  ๊ณ„์‚ฐ์€ ๊ฐ ๋„ํ˜• ํด๋ž˜์Šค๊ฐ€ ๋‹ด๋‹นํ•ด์š”. ๊ฐ€์ƒ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ๋„ ๋‹คํ˜•์„ฑ์ด ๊ตฌํ˜„๋œ ๊ฑฐ์ฃ ! ๐Ÿ‘€

CRTP๋ฅผ ์ด์šฉํ•œ ์ •์  ๋‹คํ˜•์„ฑ Shape<T> area(): double Circle computeArea(): double Rectangle computeArea(): double

์œ„ ๊ทธ๋ฆผ์„ ๋ณด์„ธ์š”. Shape ํด๋ž˜์Šค๊ฐ€ ์–ด๋–ป๊ฒŒ Circle๊ณผ Rectangle์— ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š”์ง€ ๋ณด์ด์‹œ๋‚˜์š”? ์ด๊ฒŒ ๋ฐ”๋กœ CRTP์˜ ๋งˆ๋ฒ•์ด์—์š”! โœจ

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ CRTP์˜ ๋‹ค์–‘ํ•œ ํ™œ์šฉ ์‚ฌ๋ก€๋ฅผ ์‚ดํŽด๋ดค์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? CRTP๊ฐ€ ์–ผ๋งˆ๋‚˜ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ธ์ง€ ๋Š๊ปด์ง€์‹œ๋‚˜์š”? ใ…Žใ…Ž

์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์„ ์ตํžˆ๋ฉด ์—ฌ๋Ÿฌ๋ถ„์˜ C++ ์ฝ”๋”ฉ ์‹ค๋ ฅ์€ ํ•˜๋Š˜์„ ์ฐŒ๋ฅผ ๊ฑฐ์˜ˆ์š”! ์žฌ๋Šฅ๋„ท์—์„œ๋„ ์ด๋Ÿฐ ๊ณ ๊ธ‰ ์ฃผ์ œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๊ฐ•์˜๊ฐ€ ์žˆ๋‹ค๋˜๋ฐ... ํ•œ๋ฒˆ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ์‹ค๋ ฅ ํ–ฅ์ƒ์— ํฐ ๋„์›€์ด ๋  ๊ฑฐ์˜ˆ์š”! ๐Ÿ˜‰

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” CRTP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. CRTP๊ฐ€ ๊ฐ•๋ ฅํ•œ ๋งŒํผ ์กฐ์‹ฌํ•ด์•ผ ํ•  ๋ถ€๋ถ„๋„ ์žˆ๊ฑฐ๋“ ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's go! ๐Ÿš€

โš ๏ธ CRTP ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

์ž, ์—ฌ๋Ÿฌ๋ถ„! CRTP๊ฐ€ ์–ผ๋งˆ๋‚˜ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์ธ์ง€ ์•Œ๊ฒŒ ๋˜์…จ์ฃ ? ๊ทผ๋ฐ ๋ง์ด์—์š”, ๊ฐ•๋ ฅํ•œ ๋งŒํผ ์กฐ์‹ฌํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”. ์ŠคํŒŒ์ด๋”๋งจ ์•„์ €์”จ๊ฐ€ ๊ทธ๋žฌ์ž–์•„์š”. "ํฐ ํž˜์—๋Š” ํฐ ์ฑ…์ž„์ด ๋”ฐ๋ฅธ๋‹ค"๊ณ ์š”. ใ…‹ใ…‹ใ…‹ CRTP๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์˜ˆ์š”! ๐Ÿ˜Ž

๊ทธ๋Ÿผ ์ด์ œ CRTP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์„ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณผ๊นŒ์š”?

1. ์ˆœํ™˜ ์ฐธ์กฐ ์กฐ์‹ฌํ•˜๊ธฐ

CRTP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ€์žฅ ์กฐ์‹ฌํ•ด์•ผ ํ•  ๊ฒƒ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ ์ˆœํ™˜ ์ฐธ์กฐ์˜ˆ์š”. ์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋ƒ๊ณ ์š”? ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์‚ดํŽด๋ณผ๊ฒŒ์š”!


template <typename Derived>
class Base {
    // Base์˜ ๊ตฌํ˜„
};

class Derived : public Base<Derived> {
    // Derived์˜ ๊ตฌํ˜„
};

class AnotherDerived : public Base<AnotherDerived> {
    Derived d;  // ์ด๋Ÿฐ! ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”!
};

์œ„ ์ฝ”๋“œ์—์„œ AnotherDerived ํด๋ž˜์Šค๋Š” Derived ๊ฐ์ฒด๋ฅผ ๋ฉค๋ฒ„๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์š”. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด AnotherDerived๋ฅผ ์ปดํŒŒ์ผํ•˜๋ ค๋ฉด Derived์˜ ์™„์ „ํ•œ ์ •์˜๊ฐ€ ํ•„์š”ํ•˜๊ณ , Derived๋ฅผ ์ปดํŒŒ์ผํ•˜๋ ค๋ฉด Base์˜ ์™„์ „ํ•œ ์ •์˜๊ฐ€ ํ•„์š”ํ•ด์š”. ๊ทธ๋Ÿฐ๋ฐ Base๋Š” AnotherDerived์— ์˜์กดํ•˜๊ณ  ์žˆ์ฃ . ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ "์•„ ๋ชฐ๋ผ~ ๋‚œ ๋ชปํ•ด~" ํ•˜๊ณ  ํฌ๊ธฐํ•ด๋ฒ„๋ ค์š”. ใ…‹ใ…‹ใ…‹

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ:

  • CRTP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํด๋ž˜์Šค ๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ž˜ ์‚ดํŽด๋ณด์„ธ์š”.
  • ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํด๋ž˜์Šค ๊ตฌ์กฐ๋ฅผ ์‹ ์ค‘ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜์„ธ์š”.
  • ํ•„์š”ํ•˜๋‹ค๋ฉด ์ „๋ฐฉ ์„ ์–ธ(forward declaration)์„ ์‚ฌ์šฉํ•ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด์š”.

2. ๋‹ค์ค‘ ์ƒ์† ์ฃผ์˜ํ•˜๊ธฐ

CRTP์™€ ๋‹ค์ค‘ ์ƒ์†์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํŠนํžˆ ์ฃผ์˜ํ•ด์•ผ ํ•ด์š”. ์™œ๋ƒ๊ณ ์š”? ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ์š”! ๐Ÿ˜ฑ


template <typename Derived>
class A {
public:
    void foo() { /* ๊ตฌํ˜„ */ }
};

template <typename Derived>
class B : public A<Derived> {
    // B์˜ ๊ตฌํ˜„
};

template <typename Derived>
class C : public A<Derived> {
    // C์˜ ๊ตฌํ˜„
};

class D : public B<D>, public C<D> {
    // ์ด๋Ÿฐ! ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์–ด์š”!
};

์œ„ ์ฝ”๋“œ์—์„œ D ํด๋ž˜์Šค๋Š” A์˜ foo() ๋ฉ”์„œ๋“œ๋ฅผ ๋‘ ๋ฒˆ ์ƒ์†๋ฐ›๊ฒŒ ๋ผ์š”. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์–ด๋–ค foo()๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ• ์ง€ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•ด์š”. ์ด๋Ÿฐ ์ƒํ™ฉ์„ '๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ'๋ผ๊ณ  ๋ถ€๋ฅด์ฃ .

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ:

  • CRTP์™€ ๋‹ค์ค‘ ์ƒ์†์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํด๋ž˜์Šค ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ์‹ ์ค‘ํ•˜๊ฒŒ ์„ค๊ณ„ํ•˜์„ธ์š”.
  • ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ฐ€์ƒ ์ƒ์†์„ ์‚ฌ์šฉํ•ด ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ํ•˜์ง€๋งŒ ๊ฐ€์ƒ ์ƒ์†์€ ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ์žˆ์œผ๋‹ˆ ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜์„ธ์š”.

3. ํ…œํ”Œ๋ฆฟ ์ฝ”๋“œ ๋ธ”๋กœํŠธ ์ฃผ์˜ํ•˜๊ธฐ

CRTP๋Š” ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ ๋ธ”๋กœํŠธ(code bloat) ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”. ์ฝ”๋“œ ๋ธ”๋กœํŠธ๋ž€ ํ…œํ”Œ๋ฆฟ ์ธ์Šคํ„ด์Šคํ™”๋กœ ์ธํ•ด ์‹คํ–‰ ํŒŒ์ผ์˜ ํฌ๊ธฐ๊ฐ€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์ปค์ง€๋Š” ํ˜„์ƒ์„ ๋งํ•ด์š”.


template <typename Derived>
class Base {
public:
    void complexFunction() {
        // ๋งค์šฐ ๊ธด ํ•จ์ˆ˜ ๊ตฌํ˜„
    }
};

class Derived1 : public Base<Derived1> {};
class Derived2 : public Base<Derived2> {};
class Derived3 : public Base<Derived3> {};
// ... ์ˆ˜๋งŽ์€ ํŒŒ์ƒ ํด๋ž˜์Šค๋“ค

์ด๋Ÿฐ ๊ฒฝ์šฐ, complexFunction()์ด ๊ฐ ํŒŒ์ƒ ํด๋ž˜์Šค๋งˆ๋‹ค ๋ณ„๋„๋กœ ์ธ์Šคํ„ด์Šคํ™”๋˜์–ด ์‹คํ–‰ ํŒŒ์ผ์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์งˆ ์ˆ˜ ์žˆ์–ด์š”.

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ:

  • CRTP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ…œํ”Œ๋ฆฟ ํ•จ์ˆ˜์˜ ํฌ๊ธฐ์™€ ๋ณต์žก์„ฑ์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • ๊ณตํ†ต ์ฝ”๋“œ๋Š” ๊ฐ€๋Šฅํ•œ ๋น„ํ…œํ”Œ๋ฆฟ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋กœ ์˜ฎ๊ธฐ๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”.
  • ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ตœ์ ํ™” ์˜ต์…˜์„ ํ™œ์šฉํ•ด ์ฝ”๋“œ ๋ธ”๋กœํŠธ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์–ด์š”.

4. ๋””๋ฒ„๊น…์˜ ์–ด๋ ค์›€

CRTP๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๊ณ , ์ด๋Š” ๋””๋ฒ„๊น…์„ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”. ํ…œํ”Œ๋ฆฟ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋Š” ํŠนํžˆ ์ฝ๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ฃ . ๐Ÿ˜…


template <typename Derived>
class Base {
public:
    void foo() {
        static_cast<Derived*>(this)->bar();
    }
};

class Derived : public Base<Derived> {
    // oops! bar() ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฑธ ๊นœ๋นกํ–ˆ์–ด์š”!
};

int main() {
    Derived d;
    d.foo();  // ์ปดํŒŒ์ผ ์˜ค๋ฅ˜!
}

์ด๋Ÿฐ ๊ฒฝ์šฐ, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์•„์ฃผ ๊ธด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฑ‰์–ด๋‚ผ ๊ฑฐ์˜ˆ์š”. ๊ทธ ์†์—์„œ ์ง„์งœ ๋ฌธ์ œ๋ฅผ ์ฐพ์•„๋‚ด๋Š” ๊ฑด ์‰ฝ์ง€ ์•Š์ฃ .

๐Ÿšจ ์ฃผ์˜์‚ฌํ•ญ:

  • CRTP๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์ฝ”๋“œ๋ฅผ ๋ชจ๋“ˆํ™”ํ•˜๊ณ  ํ…Œ์ŠคํŠธ๋ฅผ ์ฒ ์ €ํžˆ ํ•˜์„ธ์š”.
  • IDE์˜ ์ฝ”๋“œ ๋ถ„์„ ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•ด ์ž ์žฌ์  ๋ฌธ์ œ๋ฅผ ๋ฏธ๋ฆฌ ๋ฐœ๊ฒฌํ•˜์„ธ์š”.
  • ๋ณต์žกํ•œ ํ…œํ”Œ๋ฆฟ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ•ด์„ํ•˜๋Š” ๋Šฅ๋ ฅ์„ ํ‚ค์šฐ์„ธ์š”. (์žฌ๋Šฅ๋„ท์—์„œ ๊ด€๋ จ ๊ฐ•์˜๋ฅผ ๋“ค์–ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์•„์š”! ๐Ÿ˜‰)
CRTP ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ CRTP ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ ์ˆœํ™˜ ์ฐธ์กฐ ๋‹ค์ค‘ ์ƒ์† ์ฝ”๋“œ ๋ธ”๋กœํŠธ ๋””๋ฒ„๊น… "ํฐ ํž˜์—๋Š” ํฐ ์ฑ…์ž„์ด ๋”ฐ๋ฅธ๋‹ค"

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ CRTP ์‚ฌ์šฉ ์‹œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ๋“ค์„ ์‚ดํŽด๋ดค์–ด์š”. ์–ด๋– ์‹ ๊ฐ€์š”? ์ข€ ๋ฌด์„œ์›Œ ๋ณด์ด๋‚˜์š”? ใ…‹ใ…‹ใ…‹

ํ•˜์ง€๋งŒ ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”! ์ด๋Ÿฐ ์ฃผ์˜์‚ฌํ•ญ๋“ค์„ ์ž˜ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด, CRTP๋ฅผ ๋”์šฑ ํšจ๊ณผ์ ์ด๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ์„ ๋‹ค๋ฃฐ ์ค„ ์•ˆ๋‹ค๋Š” ๊ฑด ์—ฌ๋Ÿฌ๋ถ„์ด ์ •๋ง ์‹ค๋ ฅ ์žˆ๋Š” C++ ๊ฐœ๋ฐœ์ž๋ผ๋Š” ๋œป์ด์—์š”! ๐Ÿ‘

๋‹ค์Œ ์„น์…˜์—์„œ๋Š” CRTP์˜ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ์ตœ์‹  C++ ํ‘œ์ค€์—์„œ์˜ CRTP์— ๋Œ€ํ•ด ์•Œ์•„๋ณผ ๊ฑฐ์˜ˆ์š”. ๊ธฐ๋Œ€๋˜์ง€ ์•Š๋‚˜์š”? Let's keep going! ๐Ÿš€

๐ŸŒˆ CRTP์˜ ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ์ตœ์‹  ๋™ํ–ฅ

์ž, ์—ฌ๋Ÿฌ๋ถ„! ์ง€๊ธˆ๊นŒ์ง€ CRTP๊ฐ€ ๋ญ”์ง€, ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ฃผ์˜ํ•  ์ ์€ ๋ญ”์ง€ ์•Œ์•„๋ดค์–ด์š”. ์ด์ œ ์‹ค์ œ๋กœ ์ด ๊ธฐ์ˆ ์ด ์–ด๋””์„œ ์“ฐ์ด๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์ตœ์‹  C++ ํ‘œ์ค€์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ๋‹ค๋ค„์ง€๊ณ  ์žˆ๋Š”์ง€ ์•Œ์•„๋ณผ ์ฐจ๋ก€์˜ˆ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's dive in! ๐ŸŠโ€โ™‚๏ธ

1. ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€

CRTP๋Š” ์‹ค์ œ๋กœ ๋งŽ์€ C++ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์–ด์š”. ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณผ๊นŒ์š”?

  • Boost ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ: Boost์˜ ๋งŽ์€ ๋ถ€๋ถ„์—์„œ CRTP๋ฅผ ์‚ฌ์šฉํ•ด์š”. ํŠนํžˆ boost::intrusive์™€ boost::operators ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ๋งŽ์ด ๋ณผ ์ˆ˜ ์žˆ์ฃ .
  • ๊ฒŒ์ž„ ์—”์ง„: Unity๋‚˜ Unreal Engine ๊ฐ™์€ ๊ฒŒ์ž„ ์—”์ง„์—์„œ๋„ CRTP๋ฅผ ์‚ฌ์šฉํ•ด ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ์žˆ์–ด์š”.
  • ๊ธˆ์œต ์†Œํ”„ํŠธ์›จ์–ด: ๊ณ ์„ฑ๋Šฅ์ด ํ•„์š”ํ•œ ๊ธˆ์œต ๊ฑฐ๋ž˜ ์‹œ์Šคํ…œ์—์„œ๋„ CRTP๋ฅผ ํ™œ์šฉํ•ด ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ด๊ณ  ์žˆ์–ด์š”.

์˜ˆ๋ฅผ ๋“ค์–ด, Boost์˜ operator ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์ด๋ ‡๊ฒŒ CRTP๋ฅผ ์‚ฌ์šฉํ•ด์š”:


#include <boost/operators.hpp>

class MyInt : 
    boost::addable<MyInt>,
    boost::equality_comparable<MyInt>
{
public:
    MyInt(int n) : value(n) {}
    
    MyInt& operator+=(const MyInt& rhs) {
        value += rhs.value;
        return *this;
    }
    
    bool operator==(const MyInt& rhs) const {
        return value == rhs.value;
    }
    
private:
    int value;
};

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด +์™€ != ์—ฐ์‚ฐ์ž๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„๋„ ์ž๋™์œผ๋กœ ์ œ๊ณต๋ฐ›์„ ์ˆ˜ ์žˆ์–ด์š”. ์™„์ „ ํŽธ๋ฆฌํ•˜์ฃ ? ๐Ÿ˜Ž

2. ์ตœ์‹  C++ ํ‘œ์ค€์—์„œ์˜ CRTP

C++20๋ถ€ํ„ฐ๋Š” CRTP๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ๋“ค์ด ์ถ”๊ฐ€๋์–ด์š”. ํŠนํžˆ std::crtp ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ์ด ์ œ์•ˆ๋˜์—ˆ์ฃ . (์•„์ง ํ‘œ์ค€์— ์™„์ „ํžˆ ์ฑ„ํƒ๋˜์ง€๋Š” ์•Š์•˜์ง€๋งŒ์š”.)


#include <crtp>  // ๋ฏธ๋ž˜์˜ ์–ด๋Š ๋‚ ...

template<typename Derived>
class Base : public std::crtp<Derived, Base> {
public:
    void foo() {
        this->underlying().bar();
    }
};

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

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด static_cast๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋˜๋‹ˆ ์ฝ”๋“œ๊ฐ€ ๋” ๊น”๋”ํ•ด์ง€๊ณ  ์‹ค์ˆ˜ํ•  ๊ฐ€๋Šฅ์„ฑ๋„ ์ค„์–ด๋“ค์ฃ .

๐Ÿ’ก ์ตœ์‹  ๋™ํ–ฅ:

  • C++20์—์„œ๋Š” ์ฝ˜์…‰ํŠธ(Concepts)๊ฐ€ ๋„์ž…๋˜์–ด CRTP์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋”์šฑ ๊ฐ•๋ ฅํ•œ ์ •์  ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด์š”.
  • C++23์—์„œ๋Š” deducing this ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋  ์˜ˆ์ •์ด์—์š”. ์ด๋ฅผ ํ†ตํ•ด CRTP ํŒจํ„ด์„ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”.
CRTP์˜ ์ง„ํ™” CRTP์˜ ์ง„ํ™” C++98/03 C++11/14/17 C++20 C++23 ์ดํ›„

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

CRTP๋Š” C++์˜ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ง€๋งŒ, ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ์กฐ๊ธˆ ๊นŒ๋‹ค๋กœ์šธ ์ˆ˜ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ ๊ณ„์† ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์œผ๋‹ˆ, ์•ž์œผ๋กœ๋Š” ๋” ์‰ฝ๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์˜ˆ์š”.

์—ฌ๋Ÿฌ๋ถ„๋„ ์ด๋Ÿฐ ์ตœ์‹  ๋™ํ–ฅ์„ ๊ณ„์† ๋”ฐ๋ผ๊ฐ€๋ฉด์„œ C++ ์‹ค๋ ฅ์„ ํ‚ค์›Œ๋‚˜๊ฐ€์„ธ์š”. ์žฌ๋Šฅ๋„ท์—์„œ๋„ ์ด๋Ÿฐ ์ตœ์‹  ๊ธฐ์ˆ ๋“ค์„ ๋‹ค๋ฃจ๋Š” ๊ฐ•์˜๋“ค์ด ์žˆ์œผ๋‹ˆ ํ•œ๋ฒˆ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฑฐ์˜ˆ์š”! ๐Ÿ˜‰

์ž, ์ด์ œ CRTP์— ๋Œ€ํ•ด ์ •๋ง ๋งŽ์ด ์•Œ๊ฒŒ ๋˜์…จ์ฃ ? ๋งˆ์ง€๋ง‰์œผ๋กœ ์ •๋ฆฌ์™€ ๊ฒฐ๋ก ์„ ๋‚ด๋ ค๋ณผ๊ฒŒ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's wrap it up! ๐ŸŽ

๐ŸŽ‰ ์ •๋ฆฌ ๋ฐ ๊ฒฐ๋ก 

์™€~ ์—ฌ๋Ÿฌ๋ถ„, ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ฃ ? CRTP๋ผ๋Š” ๋ณต์žกํ•œ ์ฃผ์ œ๋ฅผ ํ•จ๊ป˜ ํƒํ—˜ํ•ด๋ดค์–ด์š”. ์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ์š”. ์ค€๋น„๋˜์…จ๋‚˜์š”? Let's go! ๐Ÿš€

1. CRTP๋ž€?

CRTP(Curiously Recurring Template Pattern)๋Š” ๊ธฐ๋ฌ˜ํ•˜๊ฒŒ ๋ฐ˜๋ณต๋˜๋Š” ํ…œํ”Œ๋ฆฟ ํŒจํ„ด์ด๋ผ๋Š” ๋œป์ด์—์š”. ํŒŒ์ƒ ํด๋ž˜์Šค๊ฐ€ ์ž๊ธฐ ์ž์‹ ์„ ๊ธฐ๋ณธ ํด๋ž˜์Šค์˜ ํ…œํ”Œ๋ฆฟ ์ธ์ž๋กœ ์ „๋‹ฌํ•˜๋Š” ํŠน์ดํ•œ ํŒจํ„ด์ด์ฃ .


template <typename Derived>
class Base {
    // ๊ตฌํ˜„
};

class Derived : public Base<Derived> {
    // ๊ตฌํ˜„
};

2. CRTP์˜ ์žฅ์ 

  • ์ปดํŒŒ์ผ ํƒ€์ž„ ๋‹คํ˜•์„ฑ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  • ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ ์—†์Œ
  • ์ •์  ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์— ์œ ์šฉ
  • ๋ฏน์Šค์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„ ๊ฐ€๋Šฅ

3. CRTP ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

  • ์ˆœํ™˜ ์ฐธ์กฐ ์กฐ์‹ฌํ•˜๊ธฐ
  • ๋‹ค์ค‘ ์ƒ์† ์‹œ ๋‹ค์ด์•„๋ชฌ๋“œ ๋ฌธ์ œ ์ฃผ์˜
  • ํ…œํ”Œ๋ฆฟ ์ฝ”๋“œ ๋ธ”๋กœํŠธ ๊ณ ๋ คํ•˜๊ธฐ
  • ๋””๋ฒ„๊น…์˜ ์–ด๋ ค์›€ ์ธ์ง€ํ•˜๊ธฐ

4. ์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€

  • Boost ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๊ฒŒ์ž„ ์—”์ง„
  • ๊ธˆ์œต ์†Œํ”„ํŠธ์›จ์–ด

5. ์ตœ์‹  ๋™ํ–ฅ

  • C++20: ์ฝ˜์…‰ํŠธ(Concepts) ๋„์ž…
  • C++23: deducing this ๊ธฐ๋Šฅ ์˜ˆ์ •
  • std::crtp ํด๋ž˜์Šค ํ…œํ”Œ๋ฆฟ ์ œ์•ˆ

๐ŸŒŸ ๊ฒฐ๋ก :

CRTP๋Š” ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ๋ณต์žกํ•œ C++ ๊ธฐ์ˆ ์ด์—์š”. ์ž˜ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ๊ณผ ์„ค๊ณ„ ๋ฉด์—์„œ ํฐ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ•ด์š”. ์ตœ์‹  C++ ํ‘œ์ค€๋“ค์€ CRTP๋ฅผ ๋” ์‰ฝ๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด์š”. ์•ž์œผ๋กœ C++ ๊ฐœ๋ฐœ์ž๋กœ์„œ ์„ฑ์žฅํ•˜๋ ค๋ฉด ์ด๋Ÿฐ ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๋“ค์„ ์ตํžˆ๊ณ  ์ ์ ˆํžˆ ํ™œ์šฉํ•  ์ค„ ์•Œ์•„์•ผ ํ•ด์š”!

CRTP ๋งˆ์Šคํ„ฐํ•˜๊ธฐ CRTP ๋งˆ์Šคํ„ฐํ•˜๊ธฐ ์ดํ•ดํ•˜๊ธฐ ์—ฐ์Šตํ•˜๊ธฐ ์ ์šฉํ•˜๊ธฐ "Practice makes perfect!"

์ž, ์—ฌ๋Ÿฌ๋ถ„! ์ด์ œ CRTP์— ๋Œ€ํ•ด ์ •๋ง ๋งŽ์ด ์•Œ๊ฒŒ ๋˜์…จ์ฃ ? ๐Ÿ˜Š

CRTP๋Š” ์ฒ˜์Œ์—๋Š” ์–ด๋ ต๊ณ  ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐฐ์šฐ๊ณ  ์—ฐ์Šตํ•˜๋‹ค ๋ณด๋ฉด, ์—ฌ๋Ÿฌ๋ถ„์˜ C++ ๋„๊ตฌ ์ƒ์ž์— ๋“ค์–ด์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ๊ฐ€ ๋  ๊ฑฐ์˜ˆ์š”. ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ CRTP๋ฅผ ์‚ฌ์šฉํ•ด๋ณด๋ฉด์„œ ๊ทธ ํž˜์„ ์ง์ ‘ ๊ฒฝํ—˜ํ•ด๋ณด์„ธ์š”!

๊ทธ๋ฆฌ๊ณ  ์žŠ์ง€ ๋งˆ์„ธ์š”. C++์€ ๊ณ„์† ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด์š”. CRTP๋„ ์•ž์œผ๋กœ ๋” ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ณ  ์•ˆ์ „ํ•ด์งˆ ๊ฑฐ์˜ˆ์š”. ์—ฌ๋Ÿฌ๋ถ„๋„ ์ด๋Ÿฐ ๋ฐœ์ „์„ ๋”ฐ๋ผ๊ฐ€๋ฉด์„œ ๊ณ„์† ์„ฑ์žฅํ•ด ๋‚˜๊ฐ€์„ธ์š”.

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