<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>myjeongjun 님의 블로그</title>
    <link>https://myjeongjun.tistory.com/</link>
    <description>그냥 공부기록</description>
    <language>ko</language>
    <pubDate>Tue, 19 May 2026 03:22:48 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>myjeongjun</managingEditor>
    <item>
      <title>[Soul Like]1.무기에 따른 애니메이션 적용</title>
      <link>https://myjeongjun.tistory.com/246</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 Unreal을 다루기 시작하면서 새롭게 알게되거나 유용한 기능들을 기록하고자한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본으로 제공되는 Third person Character에 무기만 지워주면 idle 상태는 이런 모습이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;325&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w7Hca/dJMcaad7FNu/SkzCUbQ8gUukTVD6ZxMs60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w7Hca/dJMcaad7FNu/SkzCUbQ8gUukTVD6ZxMs60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w7Hca/dJMcaad7FNu/SkzCUbQ8gUukTVD6ZxMs60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fw7Hca%2FdJMcaad7FNu%2FSkzCUbQ8gUukTVD6ZxMs60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;416&quot; height=&quot;325&quot; data-origin-width=&quot;416&quot; data-origin-height=&quot;325&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 만약 에셋에 해당 무기에 대한 idle,locomotion들이 있다면 그것들을 활용하고싶을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ALI 활용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Animation Layer Interface를 만들자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;96&quot; data-origin-height=&quot;171&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2LEDN/dJMcai4ds1U/Dj05cbZHkrpWuimUBRdU50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2LEDN/dJMcai4ds1U/Dj05cbZHkrpWuimUBRdU50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2LEDN/dJMcai4ds1U/Dj05cbZHkrpWuimUBRdU50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2LEDN%2FdJMcai4ds1U%2FDj05cbZHkrpWuimUBRdU50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;96&quot; height=&quot;171&quot; data-origin-width=&quot;96&quot; data-origin-height=&quot;171&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음으로 무기별 ABP를 만들어준다. 아무것도 들고있지 않은 상태는 ABP_Main 이다.(원래 제공되는 ABP_Unarmed라는 이름에서 변경함) 여기서는 아직 LightSword밖에 없기때문에 LightSword_Layer_ABP만 만들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;244&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8CVvE/dJMcagyBpEo/0ciWKpSXc6lWXPmKYdySl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8CVvE/dJMcagyBpEo/0ciWKpSXc6lWXPmKYdySl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8CVvE/dJMcagyBpEo/0ciWKpSXc6lWXPmKYdySl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8CVvE%2FdJMcagyBpEo%2F0ciWKpSXc6lWXPmKYdySl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;244&quot; height=&quot;180&quot; data-origin-width=&quot;244&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본격적으로 CharacterAnims_ALI에서 레이어를 정의해주는데, 당장 필요한게 idle과 Locomotion이니 둘만 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;201&quot; data-origin-height=&quot;135&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baOvSS/dJMcaaLXqnG/GKfQ13QNm4kRocVwCqkkOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baOvSS/dJMcaaLXqnG/GKfQ13QNm4kRocVwCqkkOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baOvSS/dJMcaaLXqnG/GKfQ13QNm4kRocVwCqkkOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaOvSS%2FdJMcaaLXqnG%2FGKfQ13QNm4kRocVwCqkkOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;201&quot; height=&quot;135&quot; data-origin-width=&quot;201&quot; data-origin-height=&quot;135&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 ABP들에 인터페이스를 추가하고,(빨간색 동그라미를 따라가면 됨) 각 인터페이스를 정의해준다. 기본 제공되는 idle state는 sequence player로 idle 애니메이션을 무한루프 시키고있어서 똑같이 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;894&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzhW70/dJMcajoveFC/Ju7I685bcWHXZ1dzQGj4E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzhW70/dJMcajoveFC/Ju7I685bcWHXZ1dzQGj4E1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzhW70/dJMcajoveFC/Ju7I685bcWHXZ1dzQGj4E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzhW70%2FdJMcajoveFC%2FJu7I685bcWHXZ1dzQGj4E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1335&quot; height=&quot;894&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;894&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;447&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yowid/dJMcabYoJ6l/rBJNcsH3TuCRGn8n7XN6vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yowid/dJMcabYoJ6l/rBJNcsH3TuCRGn8n7XN6vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yowid/dJMcabYoJ6l/rBJNcsH3TuCRGn8n7XN6vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYowid%2FdJMcabYoJ6l%2FrBJNcsH3TuCRGn8n7XN6vk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;362&quot; height=&quot;447&quot; data-origin-width=&quot;362&quot; data-origin-height=&quot;447&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 ABP_Main의 Idle State의 내용은 Idle_Layer로 이사시켜준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z1OHZ/dJMcagrQJPz/pjO5t0aFWDEwPddWjadLS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z1OHZ/dJMcagrQJPz/pjO5t0aFWDEwPddWjadLS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z1OHZ/dJMcagrQJPz/pjO5t0aFWDEwPddWjadLS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ1OHZ%2FdJMcagrQJPz%2FpjO5t0aFWDEwPddWjadLS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1288&quot; height=&quot;868&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 기존 ABP_Main의 움직임을 바꿀차례이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 Idle State 내부인데, sequence player 대신에 어떤 ABP냐에 따라 Idle_layer에 정의해둔 포즈가 들어가도록 바꿔준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boJJOE/dJMcabjODQI/diF0JprgBGSaJC08uhkzJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boJJOE/dJMcabjODQI/diF0JprgBGSaJC08uhkzJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boJJOE/dJMcabjODQI/diF0JprgBGSaJC08uhkzJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboJJOE%2FdJMcabjODQI%2FdiF0JprgBGSaJC08uhkzJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;778&quot; height=&quot;349&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 unarmed 상태이면 ABP_Main에 정의해둔 Idle_layer가 들어갈것이고, LightSword를 장착중이면 LightSword_Layers_ABP의 Idle_Layer가 들어갈것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 어떤 무기를 장착중인지는 어떻게 인지시킬것인가?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;327&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YwiEF/dJMcahROD84/iaSYkAsk9UZ19g1P8LtKR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YwiEF/dJMcahROD84/iaSYkAsk9UZ19g1P8LtKR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YwiEF/dJMcahROD84/iaSYkAsk9UZ19g1P8LtKR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYwiEF%2FdJMcahROD84%2FiaSYkAsk9UZ19g1P8LtKR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;860&quot; height=&quot;327&quot; data-origin-width=&quot;860&quot; data-origin-height=&quot;327&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 캐릭터의 이벤트그래프에서 Link Anim class Layers노드를 이용하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 스크린샷은 beginplay할때 테스트용으로 바로 LightSword로 바꾸도록 했지만, 정석적인방법은 무기를 손에 쥘때 이걸 변경하는것이다.(이건 알아서 넣으면 되니 생략한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공적으로 적용된듯하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1bh5G/dJMcahqMEBo/ijG3l5wkb52KxnqWTij4b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1bh5G/dJMcahqMEBo/ijG3l5wkb52KxnqWTij4b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1bh5G/dJMcahqMEBo/ijG3l5wkb52KxnqWTij4b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1bh5G%2FdJMcahqMEBo%2FijG3l5wkb52KxnqWTij4b1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;816&quot; height=&quot;532&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 에셋을보니 UE4의 스켈레톤을 베이스로 밖에안만들어져있어서 애니메이션 리타깃이라는 기능을 처음 이용해보았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/butL6j/dJMcabqzzIz/xwiKdqnNc3rRHk01tVHVOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/butL6j/dJMcabqzzIz/xwiKdqnNc3rRHk01tVHVOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/butL6j/dJMcabqzzIz/xwiKdqnNc3rRHk01tVHVOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbutL6j%2FdJMcabqzzIz%2FxwiKdqnNc3rRHk01tVHVOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1255&quot; height=&quot;711&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바꾸고싶은 스켈레톤메시, 애니메이션만 넣어주면 바로 바꿔주니 정말 편한기능이었다.&lt;/p&gt;</description>
      <category>Unreal</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/246</guid>
      <comments>https://myjeongjun.tistory.com/246#entry246comment</comments>
      <pubDate>Tue, 5 May 2026 00:15:34 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목8. 0과 NULL보다 nullptr를 선호하라.</title>
      <link>https://myjeongjun.tistory.com/245</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리터럴 0은 int이지 포인터가 아니다. 포인터만 사용할 수 있는 위치에 0이있으면 C++는 마지못해 nullptr이라는 의미로 해석하지만 최후의 수단이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NULL도 마찬가지이다. 컴파일러에따라서 int가 아닌 다른 정수 형식(long 같은)을 부여할수도있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++98에서 이 점이 야기하는 주된 문제는 포인터와 정수 형식에 대한 중복적재가 의외의 방식으로 해소된다는 점이었다.&lt;/p&gt;
&lt;pre id=&quot;code_1774273161734&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void f(int);
void f(bool);
void f(void*);

f(0); // f(void*) 가 아닌 f(int)를 호출

f(NULL); // f(void*) 가 아닌 f(int)를 호출하거나 컴파일 에러 f(void*)을 호출하는 경우는 없다&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f(NULL)의 행동에 관한 불확실성은 구체적인 형식을 컴파일러의 재량에 맡긴 결과이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NULL이 0L(long 타입)으로 정의되어있다면 int, bool, void*의 암묵적 변환 우선순위는 동일하기때문에 중의적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨋든 NULL을 nullptr의 의미로 사용하는 목적과는 다소 떨어져있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 C++98프로그래머는 포인터 형식과 정수형식들에 대해서는 중복적재를 피하라는 지침을따랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nullptr의 장점은 이것이 정수 형식이 아니라는점이다 실제 이 형식은 std::nullptr_t이다.이 자체는 또한 nullptr의 형식으로 정의된&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다.std::nullptr_t는 모든 생 포인터 형식으로 암묵적으로 변환되며, 이 덕분에 nullptr는 마치 모든형식의 포인터처럼 행동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에 나온 중복적재 함수 f를 nullptr로 호출하면 void*버전이 호출된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 nullptr은 결코 정수로는 해석되지 않기때문이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774273490526&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto result = findRecord( /* 인수들 */ );
if(result == 0) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nullptr은 명확성도 높여주는데 위의 예시를 보자면 findRecord의 반환형식을 모르면 result가 포인터 형식인지 아니면 정수 형식인지를 명확하게 말할 수 없게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 아래는 확실하게 result가 포인터임을 나타낸다.&lt;/p&gt;
&lt;pre id=&quot;code_1774273825994&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto result = findRecord( /* 인수들 */ );
if(result == nullptr) { ... }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nullptr은 템플릿이 관여할 때 특히나 빛난다.&lt;/p&gt;
&lt;pre id=&quot;code_1774273870969&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int    f1(std::shared_ptr&amp;lt;Widget&amp;gt; spw);
double f2(std::unique_ptr&amp;lt;Widget&amp;gt; upw);
bool   f3(Widget* pw);

std::mutex f1m, f2m, f3m;

using MuxGuard = std::lock_guard&amp;lt;std::mutex&amp;gt;; 

{
    MuxGuard g(f1m);
    auto result = f1(0); // 0을 널포인터로서 f1에 전달. 
}						//여기서 뮤텍스가 풀린다.

{
    MuxGuard g(f2m);
    auto result = f2(NULL); // NULL을 널포인터로서 f2에 전달. 
}						//여기서 뮤텍스가 풀린다.

{
    MuxGuard g(f3m);
    auto result = f3(nullptr); //nullptr 널포인터로서 f3에 전달. 
}						//여기서 뮤텍스가 풀린다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 두 호출을 nullptr로 안하긴했지만 작동하기는 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;shared_ptr이 0을 암묵적 변환으로 nullptr_t로 바꿔주긴 하기때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 잘 보면 호출 코드의 반복된 패턴이 존재한다. 이걸 해결하기위해 흔히 템플릿을 사용하게되는데&lt;/p&gt;
&lt;pre id=&quot;code_1774274061963&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename FuncType, typename MuxType, typename PtrType&amp;gt;
auto lockAndCall(FuncType func, MuxType&amp;amp; mutex, PtrType ptr) -&amp;gt; decltype(func(ptr))
{
    using MuxGuard = std::lock_guard&amp;lt;MuxType&amp;gt;;
    
    MuxGuard g(mutex);
    return func(ptr);
}

// C++14 버전
template&amp;lt;typename FuncType, typename MuxType, typename PtrType&amp;gt;
decltype(auto) lockAndCall(FuncType func, MuxType&amp;amp; mutex, PtrType ptr)
{
    using MuxGuard = std::lock_guard&amp;lt;MuxType&amp;gt;;
    
    MuxGuard g(mutex);
    return func(ptr);
}

auto result1 = lockAndCall(f1, f1m, 0); // 오류
auto result2 = lockAndCall(f2, f2m, NULL); // 오류
auto result3 = lockAndCall(f3, f3m, nullptr); // ok&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이젠 처음 두 호출은 컴파일되지 않는다.0으로 넘겨준 ptr이 auto를 통해 int으로 연역되기때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 f3는 nullptr을 넘거주므로 nullptr_t로 연역된다. 앞서 말했듯이 이것은 모든 포인터 형식으로 변환이 가능하기때문에 Widget*로서 암묵적 변환이 일어나 정상적으로 실행된다.&lt;/p&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/245</guid>
      <comments>https://myjeongjun.tistory.com/245#entry245comment</comments>
      <pubDate>Mon, 23 Mar 2026 23:00:06 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목7.객체 생성 시 괄호(())와 중괄호({})를 구분하라</title>
      <link>https://myjeongjun.tistory.com/244</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;C++11에서는 객체 생성 구문이 아주 다양해졌다.&lt;/p&gt;
&lt;pre id=&quot;code_1773851428010&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x(0);
int y = 0;
int z{ 0 };
int z = { 0 };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;&amp;nbsp;위의 4가지 방법 모두 똑같은 결과를 나타낸다. 그 중에서 중괄호({})로 나타낸 생성 방법을 바로 균일 초기화(uniform initialization)이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;&amp;nbsp;균일 초기화라고 부르는 이유는 어떤 상황에서든 균일하게 초기화를 할 수 있기 때문이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;C++98도 여러가지 초기화 구문을 지원했지만 원하는 초기화를 명시적으로 표현할 수 없는 상황이있었다.예를들어 1,3,5등을 담는 STL컨테이너를 직접 생성하는것은 불가능했기때문에 일단 컨테이너를 생성한 후 값들을 추가해야했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773851527802&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::vector&amp;lt;int&amp;gt; v{ 1, 3, 5 };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러가지 초기화 구문이 주는 혼동을 완화하기 위해, 그리고 그 구문들이 모든 가능한 초기화 시나리오를 포괄하지 않는다는 사실을 해결하기 위해 균일 초기화를 도입했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀더 세부적으로 말해보면 중괄호 구문은 비정적 자료 멤버의 기본 초기화 값을 지정하는데 사용가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 괄호만 이용해서 초기화하는건 불가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1773851654772&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Widget {
   ...
   private:
   int x{ 0 };
   int y = 0;
   int z(0);    /오류!
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;std::atomic객체는 &quot;=&quot;를 이용한 초기화가 불가능하다. 하지만 여전히 중괄호로 초기화하는건 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1773851729077&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::atomic&amp;lt;int&amp;gt; ai1{ 0 };
std::atomic&amp;lt;int&amp;gt; ai2(0);
std::atomic&amp;lt;int&amp;gt; ai3 = 0;   // 오류!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;좁히기 변환 방지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중괄호 초기화의 기능중하나는 내장 기능들 사이의 암묵적인 좁히기 변환을 방지해 준다는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773851819853&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;double x, y, z;
int sum1{x + y + z}; 오류! double들의 합을 int로 표현하지 못할 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;괄호나 &quot;=&quot;를 이용한 초기화는 이러한 좁히기 변환을 점검하지 않는다. 그런 점을 강제하면 레거시 코드가 더이상 컴파일 되지 않는경우가 너무 많아지기 때문이라고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1773851856851&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;double x, y, z;
int sum1(x + y + z};
int sum2 = x + y + z;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;most vexing parse&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또다른 주목할 만한 특징은 &lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;c++에는 가장 성가신 구문 해석(most vexing parse)라는 것이 있다. 이건 &quot;선언으로 해석할 수 있는 것은 항상 선언으로 해석해야 한다&quot;는 C++의 규칙에서 비롯된 하나의 부작용이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;매개변수를 중괄호로 감싸서 함수를 선언할 수 없으므로 명시적으로 생성자를 호출한다는것을 구분할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773852002353&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Widget w1(10); //인수 10으로 Widget의 생성자를 호출
Widget w2();  // w2이라는 함수 선언
Widget w3{};  // 인수 없는 생성자 호출&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 까지만 보면 장점만 있는 기능으로 보인다. 하지만 이 항목은 &quot;중괄호 초기화 구문을 선호하라&quot;가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 단점이있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중괄호 초기화는 종종 예상치 못한 행동을 보인다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 행동은 중괄호 초기치와 std::initializer_list,그리고 생성자 중복적재 해소 사이의 괴상하게 뒤얽힌 관계에서 비롯된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 중 하나가&amp;nbsp; &lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;i&gt;std::initailizer_list&lt;/i&gt;&lt;/b&gt;&lt;span&gt; 를 파라미터로 선언하면 중괄호 초기화 구문은 이상하고 &lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;i&gt;std::initailizer_list&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #666666; text-align: start;&quot;&gt;를 받는 중복 적재 버전을 &lt;b&gt;강하게 선호한다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773852285146&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Widget {
public:
    Widget(int i, bool b);
    Widget(int i, double d);
}

Widget w1(10, true);    //첫번째 생성자
Widget w2{10, true};    //첫번째 생성자
Widget w3(10, 5.0); //두번째 생성자
Widget w4{10, 5.0};   //두번째 생성자&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;std::initilizer_list의 요소들의 형식이 주어진 두 인수 형식 모두에 대해 더 나쁜 부합임에더 이런일이 생긴다.&lt;/p&gt;
&lt;pre id=&quot;code_1773852413421&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Widget {
public:
    Widget(int i, bool b);
    Widget(int i, double d);
    Widget(std::initializer_list&amp;lt;long double&amp;gt; il);
}

Widget w1(10, true);    // 이전처럼 첫 생성자 호출
Widget w2{10, true};    //10과 true를 long double로 변환 후 std::initializer_list 생성자 호출
Widget w3(10, 5.0);     // 이전처럼 두번째 생성자 호출
Widget w4{10, 5.0};     // std::initializer_list 호출&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 복사,이동 생성자도 예외는 없다. 잘못하면 가로챈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773852790877&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Widget {
public:
    ...
    operator float() const; // float로 변환
};

Widget w5(w4); // 복사 생성자 호출
Widget w6{w4}; // 초기화 리스트 생성자 호출. float로 변환되고 그 folat이 long double로 변환됨

Widget w7(std::move(w4)); // 이동 생성자 호출
Widget w8{std::move(w4)}; // 초기화 리스트 생성자 호출.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 코드는 컴파일 에러가난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중괄호 생성자를 사용하여 int, double을 bool로 변환 시키는데 이것은 좁히는 변환이고, 중괄호 초기치 안에서는 좁히기 변환을 허용하지 않는 충돌이 나므로 컴파일 에러를 발생 시킨다.&lt;/p&gt;
&lt;pre id=&quot;code_1773852855822&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Widget {
public:
    ...
    Widget(std::initializer_list&amp;lt;bool&amp;gt; il); 
};

Widget w{10, 5.0};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일러가 이런 변환을 포기하는건 인수 형식을 std::initilizer_list안의 형식으로 변환하는 방법이 아예없을 때 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어 위 코드에서 std::initilizer_list&amp;lt;bool&amp;gt;을 std::initilizer_list&amp;lt;string&amp;gt;을 받는 생성자로 대체한다면 int를 string으로 변환하는 방법은 존재하지 않으므로 비 std::initilizer_list 생성자들이 다시 후보가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 흥미로운 극단적 경우 하나를 살펴보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 생성을 지원하며, std::initilizer_list생성도 지원하는 객체를 빈 중괄호 쌍으로 생성한다고 하자. 컴파일러는 어떻게 해석할까?&lt;/p&gt;
&lt;pre id=&quot;code_1773853137419&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Widget {
public:
    Widget();
    Widget(std::initializer_list&amp;lt;int&amp;gt; il);
};

Widget w1{};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준에 따르면 이 경우는 기본생성자를 호출한다. 직, 빈 중괄호 쌍은 빈 std::initilizer_list가 아니라 인수 없음을 뜻한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빈 std::initilizer_list로 std::initilizer_list생성자를 호출하고 싶다면 중괄호 쌍을 괄호로 감싸거나 빈 중괄호쌍을 다른 중괄호 쌍으로 감싸면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1773853221327&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Widget w1({});
Widget w2{{}};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 규칙들이 과연 일상적인 프로그래밍에 도움이 될까? 이 문제에 직접 영향 받는 클래스는 std::vector이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;std::vector에는 컨테이너의 초기 크기와 컨테이너의 모든 초기 요소의 값을 지정할 수 있는 비 std::initilizer_list생성자가 있다. 그런데 컨테이너의 초기 값들을 지정할 수 있는, std::initilizer_list를 받는 생성자도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1773853341213&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::vector&amp;lt;int&amp;gt; v1(10, 20); // 값이 20인 요소 10개짜리 vector생성
std::vector&amp;lt;int&amp;gt; v2{10, 20}; // 10과 20인 두 요소를 담은 vector 생성&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 저자가 2가지를 강조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.클래스를 작성할때 std::initilizer_list 를 매개변수로 받는 생성자를 overload하는건 다른 중복 적재들과 경쟁하는것이 아니라 다른 중복적재들이 고려 대상에서 거의 완전히 제외될 정도로 가려버린다.따라서 신중히 사용하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.개발자들 사이에서 중괄호 초기화를 선호하는 사람, 그렇지 않은 사람이있다. 어느쪽이 무조건적으로 좋은것은 아니고 각각의 장단점이 존재한다. 그리고 그들또한 다른 초기화 방식이 장점을 발휘하는순간을 알고있다. 그러니 일관성있게 사용하는걸 조언한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/244</guid>
      <comments>https://myjeongjun.tistory.com/244#entry244comment</comments>
      <pubDate>Thu, 19 Mar 2026 02:11:41 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목6.명시적 형식 선언보다는 auto를 선호하라</title>
      <link>https://myjeongjun.tistory.com/243</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;항목5에서 소개했듯이 auto를 사용해서 변수를 사용하면 명시적 형식 지정보다 많은 기술적인 장점을 얻을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 가끔 auto 의 형식 연역이 의도와는 다르게 동작할수있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Widget을 인수로 받고 vector&amp;lt;bool&amp;gt; 을 반환하는 함수가 있다고 하자.&lt;/p&gt;
&lt;pre id=&quot;code_1773848480691&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::vector&amp;lt;bool&amp;gt; features(const Widget&amp;amp; w);

Widget w;
...

bool highPriority = features(w)[5];
processWidget(w, highPriority);

// auto를 사용한다면 컴파일은 가능하지만
auto highPriority = features(w)[5];
processWidget(w, highPriority); // 미정의 행동!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auto를 사용하지 않는 버전은 잘작동한다. 그러나 highpriorty의 명시적 형식을 auto로 대체하면 컴파일은 되나 미정의 행동이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜그런것일까? 일반적으로 std::vector에서 [] 연산자가 돌려주는것은 한 요소에 대한 참조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 bool은 bool&amp;amp;이 아닌 std::vector&amp;lt;bool&amp;gt;::reference형식의 객체이다. 이건 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 bool&amp;amp;을 흉내내기 위해 만들어진 프록시 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;true,false에 대한 여부는 사실 1비트만 있어도 충분하다. 그래서 std::vector&amp;lt;bool&amp;gt;은 1바이트 안에 8개의 bool을 담아서 저장하는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비트 패킹&lt;/b&gt;을 표준 위원회에서 &lt;b&gt;특수화&lt;/b&gt; 해두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 여기서 발생한다. 데이터의 최소 단위는 비트이지만, 메모리의 주소를 매길 수 있는 최소 단위는 바이트이다. 즉, 1비트 단위로는 메모리 주소(포인터)를 가질 수 없고, 그러니 당연히 참조자도 만들 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 특정 비트 하나만을가리키는 bool&amp;amp;을 반환하는 것은 물리적으로 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bool&amp;amp;를 반환할 수 없으니, C++ 표준 위원회는 operator[]가 호출되었을 때 진짜 참조자 대신 참조자처럼 행동하는 가짜 객체(Proxy Object)를 반환하도록 설계했다.&amp;nbsp; 그것이 바로 std::vector&amp;lt;bool&amp;gt;::reference이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;이 프록시 객체는 내부적으로 다음과 같은 정보를 가지고 있다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;1.자신이 속한 데이터의 &lt;b data-index-in-node=&quot;12&quot; data-path-to-node=&quot;12,0,0&quot;&gt;실제 메모리 주소 (어떤 바이트인지)&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;2.그 바이트 안에서 자신이 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;12,1,0&quot;&gt;몇 번째 비트인지 (오프셋)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;std::vector::reference의 기능중엔 bool로의 암묵적인 변환이있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책에서 이것과 관련한 것을 서술하기엔 항목의 논지와 멀어지므로 이런 정보가 있다는것을 염두해두고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드에서 []부분을 통해 std::vector&amp;lt;bool&amp;gt;reference를 돌려주지만 bool로의 암묵적인 변환이 수행된다는것을 알 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1773849168680&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;bool highPriority = features(w)[5];&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 auto로 선언하면 어떤 일이 발생하는지 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;operator[]가 std::vector&amp;lt;bool&amp;gt;::reference객체를 돌려준다는 점도 이전과 같다. 그러나 그다음은 auto에 의해 highPriority의 형식이 연역되기 때문에, highPriority가 features가 돌려준 std::vector&amp;lt;bool&amp;gt;의 5번 비트로 초기화 되지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 반환된 std::vector::reference객체는 feature를 통해 반환된 임시객체인 vector&amp;lt;bool&amp;gt;의 한 워드를 가리키는 포인터 + 그 워드에서 참조된 5번 비트에 해당하는 오프셋이있을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 임시객체인 vector&amp;lt;bool&amp;gt;은 문장 끝에서 파괴되므로 std::vector::reference가 가리키는 포인터는 dangling pointer가 되버린다. 그렇기때문에 미정의 동작이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;표준라이브러리 외에, 대리자 클래스는 표현식 템플릿이라는 기법을 사용하는 C++라이브러리들에서도 흔히 쓰인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 라이브러리들은 원래 수치 처리 코드의효율성을 개선하기 위해 개발된 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 &lt;b&gt;보이지 않는&lt;/b&gt; 대리자 클래스가 존재하는 형식이 존재하면 auto를 쓰지 않는것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 보이지 않는 대리자 클래스가 쓰이고 있는지는 어떻게 알까? 이건 대부분의 라이브러리 문서를 보면 대리자 클래스의 존재가 명시되어있는 경우가 많다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auto가 대리자 클래스 형식을 연역함을 알게되었다, 이제 auto를 버려야할까? 그렇지 않다. 명시 초기치 관용구(explicitly typed initalizer idiom)을 이용해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 말하면 초기화 표현식의 형식을 auto가 연역하길 원하는 형식으로 캐스팅하는것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1773851301920&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto highPriority = static_cast&amp;lt;bool&amp;gt;(features(w)[5]);&lt;/code&gt;&lt;/pre&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/243</guid>
      <comments>https://myjeongjun.tistory.com/243#entry243comment</comments>
      <pubDate>Thu, 19 Mar 2026 01:28:22 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목5.명시적 형식 선언보다는 auto를 선호하라</title>
      <link>https://myjeongjun.tistory.com/242</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 항목은 auto를 사용하면 어떤 상황에서 좋은지를 설명해주고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.타입이 지나치게 길때&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복자의 역참조를 통해 초기화되는 지역 변수 하나를 선언해보자면&lt;/p&gt;
&lt;pre id=&quot;code_1773669923928&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename It&amp;gt;
void dwim(It b, It e)
{
    for(; b != e; ++b)
    {
        typename std::iterator_traits&amp;lt;It&amp;gt;::value_type currValue = *b;
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형식이 std::iterator_traits&amp;lt;It&amp;gt;::value_type 이다... 이런 길이의 타입을 하나하나 치는것보다는 확실히 auto로 치는것이 나을것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.초기치를 빼먹은경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명시적 형식 선언은 초기값이 없어도 정상적으로 컴파일이된다. 하지만 auto는 초기값을 기반으로 연역을 수행하기때문에 초기값이 없으면 컴파일 에러를 발생시킨다. 이 점을 이용하여 프로그래머에게 초기값을 주지 않는 실수를 사전에 방지 할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1773670038798&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x1; // 문맥에 따라 초기화되지 않을 수 있음
auto x2; // 오류! 초기치가 꼭 필요함
auto x3 = 0; //문제 없음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.클로저를 담는 변수를 선언할 때&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;std::function은 C++11 표준 라이브러리의 한 템플릿으로, 함수 포인터 개념을 일반화 한것이다.단, 함수 포인터는 함수만 가리킬 수 있지만 std::function은 호출 가능한 객체이면 그 어떤 것도 가리킬 수 있다. 즉, 함수처럼 호출할 수 있는 것이면 그 무엇이라도 지칭 할 수 있다는말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 포인터를 만들때 그 포인터가 가리키는 함수의 형식을 지정해야 하는 것과 마찬가지로, std::function객체를 생성할 때에는 그것이 지칭할 함수의 형식을 반드시 지정해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773671154643&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::function&amp;lt;반환형식(매개변수형식1, 매개변수형식2)&amp;gt; 변수이름;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 아래와 같은식으로 std::function을 사용하려고하면 길이가 매우길어진다.&lt;/p&gt;
&lt;pre id=&quot;code_1773674828724&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::function&amp;lt;bool(const std::unique_ptr&amp;lt;Widget&amp;gt;&amp;amp;,
                   const std::unique_ptr&amp;lt;Widget&amp;gt;&amp;amp;)&amp;gt; derefUPLess = [] (const std::unique_ptr&amp;lt;Widget&amp;gt;&amp;amp; p1,
                                                                      const std::unique_ptr&amp;lt;Widget&amp;gt;&amp;amp; p2)
                                                                      {
                                                                          return *p1 &amp;lt; *p2;
                                                                      };&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auto를 쓰면 매우짧아진다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773674885375&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto derefUPLess = [] (const std::unique_ptr&amp;lt;Widget&amp;gt;&amp;amp; p1,const std::unique_ptr&amp;lt;Widget&amp;gt;&amp;amp; p2)
{ return *p1 &amp;lt; *p2;};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외형적인 차이만 있는것이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;auto로 받으면 타입이 컴파일 타임에 정확히 고정되기 때문에, 컴파일러가 함수 호출을 완전히 &lt;b data-index-in-node=&quot;62&quot; data-path-to-node=&quot;8,0,0&quot;&gt;인라인화(Inlining)&lt;/b&gt; 해버리기 쉽다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;std::function은 다형성을 지원하기 위해 내부적으로 동적 할당을 하거나 함수 포인터를 타야 해서 런타임 오버헤드가 발생한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 std::function 접근방식은 auto 접근 방식보다 메모리와 시간을 더 많이 소비하며, 때에 따라서는 메모리 부족 예외을 유발 할 수도있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.형식 단축(type shortcut)이라고 부르는 것과 관련된 문제 회피&lt;/h3&gt;
&lt;pre id=&quot;code_1773675172609&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::vector&amp;lt;int&amp;gt; v;
...
unsigned sz = v.size();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 v.size()의 실제 반환은 std::vector&amp;lt;int&amp;gt;size_type이다. 이 형식은 부호없는 정수 형식으로 지정되서 unsigned로 충분하다고 생각하지만 아키텍쳐에 따라서 std::vectorsize_type가 64비트가 될수도있어서 문제가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉,기대하지도 않은 암묵적 변환이 일어나는것을 사전에 방지해준다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 책의 저자는 또다른 걱정거리로 가독성(readalility)를 지목했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나또한 지금까지 auto는가독성을 가장 큰 이유로 잘 사용하지 않았다. 저자의 경험에 빗대어서 이런 형식 추론 기술이 대규모 업계수준 코드 기반의 작성 및 유지보수 능력과 크게 충돌하지 않았다고 말해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 대부분의 경우 IDE가 완화해준다.(이것 또한 어느정도 같은 생각이어서, 짧은 코드를 작성할때는 auto를 사용했다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체가 구체적으로 어떤 형식의 컨테이너인지는 몰라도 컨테이너인지, 스마트 포인터인지만 알면 충분한 경우가 많다고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형식을 명시적으로 표기하는것은 정확성 또는 효율성 측면에서 실수의 여지가 될 뿐, 별 다른 득이없다고한다.&lt;/p&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/242</guid>
      <comments>https://myjeongjun.tistory.com/242#entry242comment</comments>
      <pubDate>Tue, 17 Mar 2026 00:45:27 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목4.연역된 형식을 파악하는 방법을 알아두라</title>
      <link>https://myjeongjun.tistory.com/241</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;형식 연역 결과를 직접 확인하는 수단은 소프트웨어 개발 과정에서 그러한 정보가 필요한 시점에 따라 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 항목에서는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.코드를 작성,수정하는 시점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.컴파일 시점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.실행 시점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 가지의 시점에서 형식 연역 정보를 얻는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.IDE편집기(작성,수정 시점)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IDE의 코드 편집기 중에는 프로그램 개체 위에 마우스 커서를 올리면 그 개체의 형식을 표시해 주는것이 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1773576763247&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const int the Answer= 42;
auto x = theAnswer;
auto y = &amp;amp;theAnswer;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 x의 연역된 형식이 int이고 y의 연역된 형식이 cosnt int*임을 표시해 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 일이 가능하려면 편집기의 코드가 어느 정도는 컴파일 가능한 상태이어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IDE안에서 컴파일러가 실행되기때문에 컴파일러가 코드를 파싱해서 형식 연역을 수행 할 수 있을정도로 편집기의 코드가 완성 되어있지 않으면 편집기는 요청된 개체의 형식을 표시할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 형식의 경우 IDE가 알려준 정보가 쓸만하지만 복잡한 형식이 관여할때는 IDE표시 만으로는 그리 도움이 되지 않을 수 도있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.컴파일러의 진단 메세지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 컴파일러가 연역한 형식을 파악하는데 효가적인 방법은, 의도적으로 컴파일 에러가 발생하게 만드는것이다. 오류 메세지에는 문제를 일으킨 형식을 언급하기 때문에 이것을 이용하는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773576987024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
class TD;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 템필릿 하나를 정의없이 선언만 해두고 아래와 같은 코드를 적고 컴파일을 시키면 정의 부분이없어서 컴파일 오류가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773577005307&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TD&amp;lt;decltype(x)&amp;gt; xType;
TD&amp;lt;decltype(y)&amp;gt; yType;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 메세지에서&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773577029478&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;error : 'xType'은(는) 정의되지 않은 class 'TD&amp;lt;int&amp;gt;' 을(를) 사용합니다.
error : 'yType'은(는) 정의되지 않은 class 'TD&amp;lt;const int *&amp;gt;' 을(를) 사용합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.실행 시점 출력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형식 정보를 printf을 이용해서 표시하는 접근법은 실행시점에서만 사용 할 수 있지만 출력의 서식을 완전히 제어할 수 있다는 장점이있다. 이 접근방식에서 까다로운 점 하나는,원하는 형식으로부터 표시에 적합한 형태의 텍스트를 만들어 내는것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 typeid와 std::type_info::name 사용할텐데&lt;/p&gt;
&lt;pre id=&quot;code_1773577189203&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::cout &amp;lt;&amp;lt; typeid(x).name &amp;lt;&amp;lt; '\n';
std::cout &amp;lt;&amp;lt; typeid(y).name &amp;lt;&amp;lt; &quot;\n&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x나y같은 객체에 대해 typeid를 적용하면 std::type_info::name형식의 객체가 산출되며 그 객체의 name이라는 멤버 함수가 있으며 그 멤버함수는 형식의 이름을 나타내는 C스타일의 문자열을 돌려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;표준에 따르면, std::type_info__name이 의미 있는 무언가를 돌려준다는 보장은 없지만, 대체로 구현(컴파일러)들은 개발자에게 도움이 되고자 노력한다. GNU 및 Clang 컴파일러는 x의 형식이 &quot;i&quot;라고 보고하고, y의 형식이 &quot;PKi&quot;라고 보고한다. i가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;int&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이고, PK가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;pointer to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;s&gt;konst&lt;/s&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;const&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;임을 알고 나면 납득할 수 있다(두 컴파일러 모두, 이런 난도질된(mangled) 형식들을 해독해 주는 c++flit 도구를 지원합니다). Microsoft 컴파일러의 출력은 이보다 덜 난해해서, x에 대해서는 int를 y에 대해서는 int const * 보고한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;컴파일러 오류 메시지를 이용해서 형식들에 대해 정확한 결과를 얻었다고 형식 보고 문제가 완전히 해결됬다는 것은 너무 성급하다. 좀 더 복잡한 예로 알아보자&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773580336006&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(const T&amp;amp; param);                        // 호출할 템플릿 함수

std::vector&amp;lt;Widget&amp;gt; createVec();        // 팩토리 함수

const auto vw = createVec();

if(!vw.empty()) {
    f(&amp;amp;vw[0]);
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773580349451&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;using std::cout;
cout &amp;lt;&amp;lt; &quot;T =     &quot; &amp;lt;&amp;lt; typeid(T).name() &amp;lt;&amp;lt; &quot;\n&quot;;
cout &amp;lt;&amp;lt; &quot;param = &quot; &amp;lt;&amp;lt; typeid(param).name() &amp;lt;&amp;lt; &quot;\n&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 코드의 Microsoft를 통해 제공돠는 형식은&lt;/p&gt;
&lt;pre id=&quot;code_1773580377517&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;T =     class Widget const *
param = class Widget const*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다. 서로 다른 세 컴파일러가 같은 결과를 산출해낸다. 그렇다고해서 정확한 정보라는 소리는 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 템플릿 f는 param의 선언된 형식이 const T&amp;amp;이다. 그런데도 T와 param이 같다는것은 좀 이상하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;안타깝게도 std::type_info::name의 정보는 믿을만하지않다. 더 나아가 표준을 준수하려면 틀리게 보고할 필요가있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;준에 따르면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;std::type_info::name은 반드시 주어진 형식을 마치 템플릿 함수에 값 전달 매개변수로서 전달된 것처럼 취급해야한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;항목1에서 설명하듯이, 값 전달의 경우 형식이 참조이면 참조성이 무시되며, 참조 제거후 const 역시 무시됩니다. 그래서 const Widget* const&amp;amp;인 param의 형식이 const Widget*으로 보고된것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 결과는 이런 도구의 결과는 유용하지도 않고 정확하지도 않을 수 있으므로 C++의 형식 연역 규칙을 제대로 이해하는 것이 필요하다.&lt;/p&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/241</guid>
      <comments>https://myjeongjun.tistory.com/241#entry241comment</comments>
      <pubDate>Sun, 15 Mar 2026 22:16:08 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목3.decltype의 작동 방식을 숙지하라</title>
      <link>https://myjeongjun.tistory.com/240</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;decltype은 declared type이란 뜻으로, 변수나 표현식의 형시을 아무 수정 없이 보고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&quot;C++11에서 decltype은 함수의 반환 형식이 그 매개변수 형식들에 의존하는 함수 템플릿을 선언할 때 주로 사용됩니다.. 예를 들어, 컨테이너 하나와 색인 하나를 받고, 우선 사용자를 인증한 후 대괄호 색인화를 통해서(즉, 컨테이너[색인] 구문) 컨테이너의 한 요소를 돌려주는 함수를 작성한다고 가정하겠습니다. 이러한 함수의 반환 형식은 반드시 색인화 연산의 반환 형식과 동일해야 합니다.&quot;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773389731265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename Container. typename Index&amp;gt;                   
auto authAndAccess(Container&amp;amp; c, Index i) -&amp;gt; decltype(c[i])
{
    authenticateUser();
    return c[i];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대체로 형식 T의 객체들을 담은 컨테이너에 대한 operator[]연산은 T&amp;amp;를 돌려준다. 예를들어 deque가 그렇고, vector도 거의 항상 그렇다. 그중에 vector&amp;lt;bool&amp;gt;에 대한 operator[]는 bool&amp;amp;이 아니라 완전히 새로운 객체를 반환한다. 왜그런지는 항목6에서 알아보고, 중요한점은 컨테이너의 operator[]의 반환 형식이 컨테이너에 따라 달리질 수 있다는점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 decltype을 사용하면 그런 함수의 반환 형식을 손쉽게 표현 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서 auto는 형식 연역이 아니고 후행 반환 형식(trailing return type)구문의 일부일 뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;C++11에서는 람다 함수가 한 문장으로 이뤄져 있다면 그 반환 형식의 연역을 허용하며, C++14는 허용 범위를 확장하여 모든 람다와 모든 함수의 반환 형식 연역을 허용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773390038275&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename Container, typename Index&amp;gt;
auto authAndAccess(Container&amp;amp; c, Index i)
{
    authenticateUser();
    return c[i];               //반환 형식은 c[i]로 부터 연역된다.
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이렇게 사용하면 이전 후행 반환 형식과는 다르게, auto는 형식 연역이 일어남을 뜻하는 용도로 돌아오게된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목2를 읽어봤다면, 함수 반환 형식이 auto여도 실제로는 템플릿 형식 연역 규칙을 따른다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 템플릿을 이용한 아래 코드는 정상적으로 컴파일 되지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c[i]까진 int&amp;amp;이나 템플릿 형식 연역을 적용한 최종적으로 반환되는 타입은 int가 된다.(참조를 없앤다는 규칙이 있으므로)&lt;/p&gt;
&lt;pre id=&quot;code_1773390240334&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std:deque&amp;lt;int&amp;gt; d;
...
authAndAccess(d,5) = 10;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반환값으로서의 int는 하나의 오른값이며 결과적으로 오른값에 10을 대입하려고해서 오류가나는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 템플릿 형식 연역 규칙으로 반환하는 것입니다. 그래서 C++14에서는 &lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;decltype(auto&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;)을 통해 decltype형식 연역 규칙들이 적용되어야 함을 나타낼 수 있게해주었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773390419695&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename Container, typename Index&amp;gt;        
decltype(auto) AuthAndAccess(Container c, Index i)
{
    authenticateUser();
    return c[i];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 끝내면 좋겠지만 책에서는 개운치 않은 상황이 2개있다고 말해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.함수의 매개변수는 비const객체에 대한 왼값 참조로서 함수에 전달된다. 이 때문에 함수에 오른값 컨테이너는 넣을 수 없다는것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1773390716486&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::deque&amp;lt;std::string&amp;gt; makeStringDeque();         

// makeStringDeque가 돌려준 deque의 다섯 번째 원소의 복사본을 만든다.
auto s = authAndAccess(makeStringDeque(), 5);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 오른값 컨테이너는 임시적인 값이므로 함수 끝에서 파괴되는 값이긴하지만, 임시 컨테이너의 한 요소의 복사본을 만들고 싶을 수도있기때문에 이런 케이스까지 고려해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 용법을 지원하려면 오른값도 받아줄수있게 &amp;amp;&amp;amp;을 사용해야한다. 이것은 왼값과 오른값이 모두 묶일 수 있는 참조 매개변수, 보편 참조 매개변수이다.&lt;/p&gt;
&lt;pre id=&quot;code_1773390740304&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename Container, typename Index&amp;gt;
decltype(auto) authAndAccess(Container&amp;amp;&amp;amp; c, Index i);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;decltype이 아주 가끔 예상 밖의 결과를 제공한다. decltype을 이름에 적용하면, 그 이름에 대해 선언된 형식이 산출된다. 대체로 이름은 왼값 표현식이나,그 점이 decltype의 행동에 영향을 주지 않는다. 그런데 이름보다 조금 복잡한 왼값 표현식에 대해서는 항상 왼값 참조를 보고한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773390948778&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;decltype(auto) f1()
{
    int x = 0;
    retrun x;                // decltype(x)는 int이므로 f1은 int를 반환
}

decltype(auto) f2()
{
    int x = 0;
    return (x);                // decltype((x))는 int&amp;amp;이므로 f2는 int&amp;amp;를 반환
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/240</guid>
      <comments>https://myjeongjun.tistory.com/240#entry240comment</comments>
      <pubDate>Fri, 13 Mar 2026 17:36:11 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목2.auto형식 연역 규칙을 숙지하라</title>
      <link>https://myjeongjun.tistory.com/239</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;항목1에서 템플릿 형식 연역을 배웠으니 이제 auto 형식의 연역에 대해 배워보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 한 가지 예외를 제외하면 auto형식 연역이 곧 템플릿 형식 연역이다. 템플릿은 템플릿 함수와 매개변수가 관여하지만 auto는 그렇지도 않는데 템플릿과 거의 똑같이 작동한다. 우연의 일치인가? 나 또한 궁금했지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저자는 이런것에 대한 논의는 그다지 중요하지 않다고 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제로 봐보자&lt;/p&gt;
&lt;pre id=&quot;code_1773229866260&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto x = 27;

const auto cx = x;

const auto&amp;amp; rx = x;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 x의 형식 지정자는 auto 그자체이다. cx의 경우 const auto, rx에서는 const auto&amp;amp;이다. 이것들을 연역할때 컴파일러는 마치 선언마다 템플릿 함수 하나와 해당 초기화 표현식으로 그 템플릿 함수를 호출하는 구문이 존재하는것 처럼행동한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773229938340&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;                    // x의 형식을 연역하기 위한 개념적인 템플릿
void func_for_x(T param);

func_for_x(27);                    // 개념적인 호출 : param에 대해 연역된 형식이 바로 x의 형식

template&amp;lt;typename T&amp;gt;                    // cx의 형식을 연역하기 위한 개념적인 템플릿
void func_for_cx(const T param);

func_for_cx(x);                    // 개념적인 호출 : param에 대해 연역된 형식이 곧 cx의 형식

template&amp;lt;typename T&amp;gt;                    // rx의 형식은 역역하기 위한 개념적인 템플릿
void func_for_x(const T&amp;amp; param);

func_for_rx(x);                    // 개념적인 호출 : param에 대해 연역된 형식이 바로 rx의 형식&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 항목에서 논한 3가지의 경우&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;경우 1 : 형식 지정자가 포인터나 참조 형식이지만 보편 참조는 아닌 경우&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;경우 2 : 형식 지정자가 보편 참조인 경우&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;경우 3 : 형식 지정자가 포인터도 아니고 참조도 아닌 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것또한 똑같이 적용됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773230152471&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto x = 27; // 경우 3
const auto cx = x; // 경우 3
const auto&amp;amp; rx = x; // 경우 1

auto&amp;amp;&amp;amp; uref1 = x;        // x는 int이면서 왼값이므로 uref1의 형식은 int&amp;amp;
auto&amp;amp;&amp;amp; uref2 = cx;        // cx는 const int이면서 왼값이므로 uref2의 형식은 const int&amp;amp;
auto&amp;amp;&amp;amp; uref3 = 27;    // 27은 int이면서 오른값이므로 uref3의 형식은 int&amp;amp;&amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경우 3일때, 배열이 포인터로 붕괴하거나 함수가 함수 포인터로 붕괴하는 등의 경우또한 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773230288746&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const char name[] = &quot;R, N. Briggs&quot;;    // name의 형식은 const char[13]
auto arr1 = name;                            // arr1의 형식은 const char*
auto&amp;amp; arr2 = name;                            // arr2의 형식은 const char (&amp;amp;)[13]

void someFunc(int, double);                // someFunc의 형식은 void(int, double)
auto func1 = someFunc;                    // func1의 형식은 void(*)(int, double)
auto&amp;amp; func2 = someFunc;                    // func2의 형식은 void(&amp;amp;)(int, double)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다른 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++에서는 아래와 같은 초기화 방법외에 중괄호 초기화 방법이 존재합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773230326210&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x1 = 27;
int x2(27);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773230358048&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int x3 = {27};
int x4{27};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 int를 auto로 고쳐도 문제 없이 컴파일 됩니다. 하지만 3번째와 4번째는 연역되는 타입이 int가아닌 initializer_list&amp;lt;int&amp;gt;로 연역됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773230384676&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto x1 = 27;
auto x2(27);
auto x3 = {27};
auto x4{27};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 auto에 대한 특별한 형식 연역 규칙이 있기때문입니다. auto로 선언된 변수의 초기치가 중괄호 쌍으로 감싸진 형태이면 연역된 형식은 initializer_list입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 여기서 수정해야할 사항이있는데 2014년 11월에 C++표준위원회는 auto와 직접 초기화 구분을 이용한 중괄호 초기치에 대한 특별한 연역 규칙을 제거하자는 제안을 받아들였습니다. 즉, x4의 초기화 방식은 int로 연역하자는 제안이죠&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 실제로 visual studio에서 실험해보니 서로 다른 값이 나오더군요&lt;/p&gt;
&lt;pre id=&quot;code_1773230624519&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;typeinfo&amp;gt;
using namespace std;

int main()
{
    auto x = {27};

    auto y{ 27 };
 
    cout&amp;lt;&amp;lt;typeid(x).name()&amp;lt;&amp;lt;'\n';
    cout &amp;lt;&amp;lt; typeid(y).name();


    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buMk6x/dJMcafZ5BjL/XrxUSSJzLCYI7ZnIJB0k71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buMk6x/dJMcafZ5BjL/XrxUSSJzLCYI7ZnIJB0k71/img.png&quot; data-alt=&quot;결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buMk6x/dJMcafZ5BjL/XrxUSSJzLCYI7ZnIJB0k71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuMk6x%2FdJMcafZ5BjL%2FXrxUSSJzLCYI7ZnIJB0k71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;299&quot; height=&quot;44&quot; data-origin-width=&quot;299&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auto형식 연역과 템플릿 형식 연역은 이처럼 중괄호 초기치가 관여할때만 차이를 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773230787265&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto x = {11,23,9};            // x의 형식은 std::initializer_list&amp;lt;int&amp;gt;

template&amp;lt;typename T&amp;gt;           //x의 선언에 해당하는 매개변수
void f(T Param);			//선언을가진 템플릿

f({ 11, 23, 9 });                // 오류 ! T에 대한 형식을 연역할 수 없음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;하지만, param의 형식이 어떤 알려지지 않은 T에 대한 std::initializer_list&amp;lt;T&amp;gt;인 템플릿에 그 중괄호 초기치를 전달하면 템플릿 형식 연역 규칙들에 의해 T의 형식이 제대로 연역됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773230820519&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(std::initiliaer_list&amp;lt;T&amp;gt; initList);

f({11, 23, 9});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;auto에넌 중괄호 초기치에 대한 특별한 규칙이있지만 템플릿 형식 연역에는 없는 이유가 궁금할수도있지만 저자 또한 설득력있는 원인은 발견하지 못했다고 한다. 그러나 규칙은 규칙이며 따라서 auto를 이용해서 변수를 선언하면서 그 변수를 중괄호 초기치로 초기화 할때에는 변수의 형식이 std::initializer_list로 연역된다는 점을 기억하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++14에서는 함수 반환 형식을 auto로 지정해서 컴파일러가 연역하게 만들 수 있으며,람다의 매개변수 선언에 auto를 사용하는 것도 가능하다. 그러나 auto의 그러한 용법들에는 auto 형식의 연역이 아니라 템플릿 형식 연역의 규칙들이 적용된다.그래서 중괄호 초기치를 돌려주는 함수의 반환 형식을 auto로 지정하면 컴파일이 실패한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773231038357&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;auto createInitList()
{
    return {1,2,3};            // 오류 ! {1, 2, 3}의 형식을 연역할 수 없음
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;C++14 람다의 매개변수 형식 명세에 auto를 사용하는 경우에도 마찬가지 이유로 컴파일이 실패합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773231057356&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;std::vector&amp;lt;int&amp;gt; v;
...

auto resetV = [&amp;amp;v](const auto&amp;amp; newValue){v = newValue};

...

resetV({1,2,3});        // 오류 ! {1,2,3}의 형식을 연역할 수 없습니다.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/239</guid>
      <comments>https://myjeongjun.tistory.com/239#entry239comment</comments>
      <pubDate>Wed, 11 Mar 2026 21:11:31 +0900</pubDate>
    </item>
    <item>
      <title>[Effective Modern C++]항목1.템플릿 형식 연역 규칙을 숙지하라</title>
      <link>https://myjeongjun.tistory.com/238</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;C++98에서는 형식 연역(type deduction)에 관한 규칙들이 한 종류밖에 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++11에서는 그 규칙 집합을 조금 수정하고, 새로운 규칙 집합을 두 개 더 추가했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나는 auto를 위한 규칙들이고 또 하나는 delctype을 위한 규칙들이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Modern C++의 강력한 기능 중 하나인 auto는 템플릿에 대한 형식 연역을 기반으로 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 우선 템플릿 에 대한 형식 연역을 이해해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773061529105&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(ParamType param);

f(expr);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴파일 도중 컴파일러는 expr을 이용해서 T와 ParamType에 대한 형식을 연역한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ParamType의 경우 T에 const나 참조 한정사 같은 수식어들이 붙은것 까지를 지칭한다.&lt;/p&gt;
&lt;pre id=&quot;code_1773061885845&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(const T&amp;amp; param);

int x = 0;
f(x);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 통해 이해해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f 함수의 argument로 int 형식의 x를 넘겨주었다. 이 경우 T는 int가 될것이고 ParamType은 수식어가 붙은 const int&amp;amp;가 될 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금은 argument와 연역된 T의 형식이 int로 일치한다. 항상 이럴것 같지만 그렇지 않은 경우가 3가지 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.ParamType이 포인터 또는 참조 형식이지만 보편 참조는 아닌경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보편 참조에 대해서는 나중에 설명하고, 일단은 lvalue나 rvalue와는 다른것이라는 것만 알아두자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.ParamType이 보편 참조인 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.ParamType이 포인터도 아니고 참조도 아닌 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세가지 시나리오를 하나씩 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1.ParamType이 포인터 또는 참조 형식이지만 보편 참조는 아닌경우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 형식 연역은 다음과 같이 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.만일 argument가 참조 형식이면 참조 부분을 무시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.그런 다음 argument의 형식을 ParamType에 대해 패턴 부합(pattern-matching) 방식으로 대응시켜 T의 형식을 결정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1773062297414&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T&amp;amp; param);      
int x = 27        
const int cx = x       
const int&amp;amp; rx = x&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773062364202&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;f(x);            // T는 int, param의 형식은 int&amp;amp;
f(cx);            // T는 const int, param의 형식은 const int&amp;amp;
f(rx);            // T는 const int, param의 형식은 const int&amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인터 또한 동일하게 적용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1773064929856&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T* param);

int x = 27;
const int* px = &amp;amp;x;

f(&amp;amp;x);            // T는 int, param은 int*
f(px);            // T는 const int, param은 const int*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;말로 설명하니 이렇지만 직관적으로 이런 규칙을 이해하지 않고있더라도, 참조가 없어져야 자연스러운 부분이 많아진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773065159100&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T* param)
{
	T v; //임시 객체를 함수 body에서 만들어야하는 상황이 있다면, T가 참조 형식인것은 부자연스러울 것이다

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2.ParamType이 보편 참조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;템플릿이 보편 참조 매개변수를 받는 경우에는 상황이 달라진다. 보편 참조를 받는 매개변수의 선언은 오른값 참조와 같은 모습이지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;왼값 인수가 전달되면 오른값 참조와는 다른 방식으로 행동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;expr이 왼값(l-value)이면, T와 ParamType 둘 다 왼 값 참조로 연역된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;l-value일때의 규칙은 이중적으로 비정상적인데, 첫째로 템플릿 형식 연역에서 위에서 말한것과 달리 T가 참조 형식으로 연역되는 유일한 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘째로 ParamType의 선언 구문은 오른값 참조와 같은 모습이지만,연역된 형식은 왼값 참조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773065505326&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;type name T&amp;gt;
void f(T&amp;amp;&amp;amp; param);        // param이 보편 참조

int x = 27;
const int cx = x;
const int&amp;amp; rx = x;

f(x);            // T는 int&amp;amp;, param은 int&amp;amp;
f(cx);            // T는 const int &amp;amp;, param은 const int &amp;amp;
f(rx);            // T는 const int &amp;amp;, param은 const int &amp;amp;
f(27);            // T는 int, param은 int&amp;amp;&amp;amp;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것에 대한 설명은 항목 24에서 하고 지금은 이런 경우 보편 참조인 경우는 조금 다르게 동작한다고만 알고있자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;3.ParamType이 포인터도 아니고 참조도 아님&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 좀 더 직관적인 상황인데 포인터도 아니고 참조도 아니면 함수에 argument가 값으로 전달(pass by value)라는 말과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이건 C++을 조금 알고있다면 param은 argument의 복사본이기 때문에 완전히 새로운 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 개념을 알고있다면 아래 규칙들이 당연하다고 느껴질것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.이전처럼,expr의 형식이 참조이면,참조 부분은 무시된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.expr의 참조성을 무시한 후,만일 expr이 const이면 그 const 역시 무시한다.만일 volatile이 그것도 무시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773065881419&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T param);

int x = 27;
const int cx = x;
const int&amp;amp; rx = x;

f(x);            // T는 int, param은 int
f(cx);            // T는 int, param은 int
f(rx);            // T는 int, param은 int&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 const 객체를 가리키는 const 포인터는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인터 자체는 값으로 전달되지만 포인터가 가리키는 것의 const성은 보존된다.&lt;/p&gt;
&lt;pre id=&quot;code_1773066033865&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T param);

const char* const ptr = &quot;Fun with pointers&quot;;    // ptr의 형식은 const char* const

f(ptr);            // T는 const char*, param은 const char*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배열 인수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열과 포인터는 어떤 경우에는 구분하지 않고 사용할때도있다. 하지만 이 둘은 다른 형식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼에도 불구하고 맞바꿔 쓸수있어 보이는건 많은 문맥에서 배열이 배열의 첫 원소를 가리키는 포인터로 붕괴(decay)한기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 decay 때문에 다음과 같은 코드가 오류 없이 컴파일된다.&lt;/p&gt;
&lt;pre id=&quot;code_1773075512829&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const char name[] = &quot;J. P. Briggs&quot;;    // type : const char[13]

const char* ptrToName = name;    // 배열이 포인터로 붕괴됩니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 배열을 값 전달 매개변수를 받는 템플릿에 전달한다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773075692413&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T param); //하지만 배열 형식의 함수 매개변수 라는것은 없다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 아래와 같은 선언은 적법하지만, 이 경우 배열선은 하나의 포인터로 취급된다.&lt;/p&gt;
&lt;pre id=&quot;code_1773075619448&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void func(int param[]);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1773075745475&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void func(int* param) //이 것과 동일하다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 배열 매개변수와 포인터 매개변수의 동치성은 C에서부터 시작한 개념이어서 배열 형식과 포인터 형식이 같다는 환상은 이 점에서 비롯된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 매개변수 선언이 포인터 매개변수처럼 취급되므로, 템플릿 함수에 값으로 전달되는 배열의 형식은 포인터 형식으로 연역된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 한 가지 교묘한 트릭이있는데,매개변수를 진짜 배열로 선언할 수는 없지만, 배열에 대한 참조로 선언할 수는 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1773076049166&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
template&amp;lt;typename T, std::size_t N&amp;gt;
constexpr std::size_t arraySize(T (&amp;amp;)[N]) noexcept
{
    return N;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 예시로 설명하자면 T는 const char[13]로 연역되고 매개변수자체는 const char(&amp;amp;)[13]으로 연역된다.&lt;/p&gt;
&lt;pre id=&quot;code_1773076130351&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt;typename T&amp;gt;
void f(T&amp;amp; param);

const char name[] = &quot;J. P. Briggs&quot;;

f(name);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;함수 인수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포인터로 붕괴하는것은 배열뿐만아니라 함수 형식도 함수 포인터로 붕괴 할 수있으며, 지금까지 배열에 대한 형식 연역과 관련해서 논의한 모든것은 함수에 대한 형식 연역에, 그리고 함수 포인터로의 붕괴에 적용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1773076253339&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void someFunc(int, double);        // someFunc는 함수이며, 형식은 void(int,double)

template&amp;lt;typename T&amp;gt;
void f1(T param);            // f1은 값 전달 방식

template&amp;lt;typename T&amp;gt;
void f2(T&amp;amp; param);            // f2는 참조 전달 방식

f1(someFunc);            // param은 함수 포인터로 연역됨, 형식은 void (*)(int, double)
f2(someFunc);            // param은 함수 참조로 연역됨, 형식은 void(&amp;amp;)(int, double);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 응용에서 이 점때문에 뭔가 달라진건 딱히 없지만 배열에서 포인터로의 붕괴를 알고있으면 이 점도 알아두는게 좋다.&lt;/p&gt;</description>
      <category>C++</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/238</guid>
      <comments>https://myjeongjun.tistory.com/238#entry238comment</comments>
      <pubDate>Tue, 10 Mar 2026 01:14:31 +0900</pubDate>
    </item>
    <item>
      <title>[그래픽스] 6.자체 엔진 제작기</title>
      <link>https://myjeongjun.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;시험 기간도 끝나서 다시 작업을 재개해봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 다시 작업하니 기억이 가물가물한데 그래픽스 파이프라인을 복습할겸 편집용 Scene창이외에 게임 상황을 보여주는 Game창을 만들어보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;945&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FZKYQ/dJMcabCPNnm/TobYkr3h1I1mIBI0LyjeLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FZKYQ/dJMcabCPNnm/TobYkr3h1I1mIBI0LyjeLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FZKYQ/dJMcabCPNnm/TobYkr3h1I1mIBI0LyjeLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFZKYQ%2FdJMcabCPNnm%2FTobYkr3h1I1mIBI0LyjeLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1249&quot; height=&quot;945&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;945&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Scene창만 존재하는모습&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 위해 마주할 문제를 적어보자면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.Game창을 위한 카메라가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.그 카메라가 담은 장면을 Game창에 옮겨와야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지를보면 Scene창을 위한 카메라는 오브젝트로 취급되지 않기때문에 Hierarchy창에 존재하지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 앞으로 구현할 Game 창을 위한 카메라는 오브젝트로 취급되며, 카메라가 없을시 Game 창에는 아무것도 그려지지 않아야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 시점에서 인지한 추가적인 필요사항은, 씬을 생성할때 유니티는Main Camera와 Directional Light를 기본적으로만들어준다는것이다. 그러므로 씬을 생성하는 함수에 우선 기본적으로 카메라를 만들어주는 기능또한 추가해줬다. (현재는 씬을 저장하고 로드하는 기능을 만들어놓지 않았기때문에 엔진 프로그램을 처음 실행했을때 초기화 되는 씬에 대한 이야기이다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/71RYp/dJMcaiBUZOP/QsPm3cy8eSYmb2dKGo43E1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/71RYp/dJMcaiBUZOP/QsPm3cy8eSYmb2dKGo43E1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/71RYp/dJMcaiBUZOP/QsPm3cy8eSYmb2dKGo43E1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F71RYp%2FdJMcaiBUZOP%2FQsPm3cy8eSYmb2dKGo43E1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;251&quot; height=&quot;172&quot; data-origin-width=&quot;251&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/460357956&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/HsuHx/hyZQ9hEIYv/vrykMOXxudvw4NhcYpQ5t0/img.jpg?width=1248&amp;amp;height=946&amp;amp;face=0_0_1248_946,https://scrap.kakaocdn.net/dn/bapHbN/hyZRb7AWDd/NQ6uZA3z0yMs6rEuHr3hp1/img.jpg?width=1248&amp;amp;height=946&amp;amp;face=0_0_1248_946&quot; data-video-width=&quot;860&quot; data-video-height=&quot;652&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;652&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot; data-video-title=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/460357956?service=daum_tistory&quot; width=&quot;860&quot; height=&quot;652&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 되긴했다... 근데 문제는 많다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구현의 대략적인 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.Scene view를 만들때 RTV(Rendering Target view),DSV(depth stencil view)를 설정해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 Game View를 그리는 차례가 올때도 설정해주도록 변경해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.어차피 같은 월드를 그려주므로 VS나 PS는 동일하게 사용한다. 차이점은 ConstantBuffer에 넣어주는 값이다. Game View에 그려지는 화면은 Main Camera시점에서 바라보는 화면이기때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.두 화면을 그리는 사이에 백버퍼 초기화도 해줘야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제점들&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.Game view 비율이 이상함 -&amp;gt; aspect 설정 이상&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.카메라 회전이 이상함 -&amp;gt; 회전 함수의 인자를 잘못넣어준것으로 보임&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.Game view 창 해상도를 일정이상 늘리면 Scene view 화면으로 옮겨가버림&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-&amp;gt;디버깅에 2시간 걸린거같다.... 단순한 오타 한줄로 발생한 현상, DSV에 설정한 크기하고 RTV에서 설정한 크기가 다르면 화면에 아예 그리지 않는다. 코드를 잘못적어서 Game창의 DSV를 반환하는 GetGameDSV 함수의 반환값을 Scene창의 DSV를 반환하고있었다....(그래도 새로운거 알았으니 위안으로...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/460358453&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/OR8Ip/hyZQ0kHbEA/qB28m8KXVugg09CkGEDxI0/img.jpg?width=1232&amp;amp;height=964&amp;amp;face=0_0_1232_964,https://scrap.kakaocdn.net/dn/bojw14/hyZQ6d9TXB/lPXtum368tJh7hFkWFKXDK/img.jpg?width=1232&amp;amp;height=964&amp;amp;face=0_0_1232_964&quot; data-video-width=&quot;860&quot; data-video-height=&quot;673&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;673&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;'myjeongjun 님의 블로그'에서 업로드한 동영상&quot; data-video-play-service=&quot;daum_tistory&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/460358453?service=daum_tistory&quot; width=&quot;860&quot; height=&quot;673&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;씬내에 여러개의 카메라를 둘 수도있다. 여러개의 카메라를 기존 Scene의 object 벡터에 넣어놓고 관리할것인가?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유니티 카메라에는 depth라는 옵션이 존재한다, 이것은 씬내에 여러개의 카메라가 존재할때, 어떤 카메라의 시점을 Game창에 띄울지 우선순위를 정해주는 옵션이다. 만약 카메라를 다른 오브젝트와 동일하게 취급한다고 가정하고, 저 옵션을 건드렸을 경우 전체 오브젝트 벡터에서 카메라 컴포넌트를 가진 오브젝트를 찾고, 거기서 다시 depth를 기반으로 Game창에 그릴 카메라를 선별해야할것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;318&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U2zKH/dJMcabbL1dj/GKHuTzrEi4rcDCDmUgqjO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U2zKH/dJMcabbL1dj/GKHuTzrEi4rcDCDmUgqjO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U2zKH/dJMcabbL1dj/GKHuTzrEi4rcDCDmUgqjO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU2zKH%2FdJMcabbL1dj%2FGKHuTzrEi4rcDCDmUgqjO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;618&quot; height=&quot;318&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;318&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 Game창을 그릴때 이런 과정을 거치는건 비효율적이므로 간단하게 캐싱을 해볼것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;씬내의 카메라들만 담은 벡터를 우선순위대로 정렬하고, 가장 우선순위가 높은 카메라를 Game창에 그린다,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵션 변경에 대한 해결책은 dirty 변수를 두어서 옵션병경이 일어나거나 카메라 오브젝트를 생성하게 되면 카메라 전용 벡터에도 변경이 일어나는 식으로 하면 될거같다!&lt;/p&gt;</description>
      <category>그래픽스</category>
      <author>myjeongjun</author>
      <guid isPermaLink="true">https://myjeongjun.tistory.com/233</guid>
      <comments>https://myjeongjun.tistory.com/233#entry233comment</comments>
      <pubDate>Wed, 31 Dec 2025 04:36:25 +0900</pubDate>
    </item>
  </channel>
</rss>