<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>데브웁스</title>
    <link>https://devoops.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 14 May 2026 13:54:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>더해리</managingEditor>
    <item>
      <title>Claude Code를 활용한 고품질 애플리케이션 개발 가이드</title>
      <link>https://devoops.tistory.com/168</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 터미널에서 동작하는 에이전틱 코딩 도구로, 코드베이스를 이해하고 자연어 명령을 통해 파일 편집, 명령 실행, Git 워크플로우까지 수행합니다. 이 가이드는 Claude Code를 활용하여 &lt;b&gt;프로덕션 수준의 고품질 애플리케이션&lt;/b&gt;을 체계적으로 개발하기 위한 절차와 베스트 프랙티스를 정리합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Phase 1: 프로젝트 인프라 구축&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고품질 결과물의 80%는 Claude Code에게 제공하는 컨텍스트 품질에 의해 결정됩니다. 코드 한 줄 작성하기 전에 프로젝트 인프라를 먼저 세팅하세요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.1 CLAUDE.md 설정 &amp;mdash; 가장 중요한 단일 작업&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CLAUDE.md는 Claude Code가 세션 시작 시 자동으로 읽는 프로젝트 메모리 파일입니다. 프로젝트의 컨벤션, 아키텍처, 기술 스택을 명시해두면 Claude가 일관된 코드를 생성합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# CLAUDE.md

## 프로젝트 개요
- 프로젝트명: my-service
- 설명: 주문 관리 마이크로서비스

## 기술 스택
- Java 21 + Kotlin
- Spring Boot 3.4 (Spring MVC, Spring Data JPA)
- Gradle (Kotlin DSL)
- PostgreSQL, Redis
- RestClient (WebClient 대신 사용)

## 아키텍처 규칙
- Layered Architecture: Controller &amp;rarr; Service &amp;rarr; Repository
- DTO는 record(Java) 또는 data class(Kotlin) 사용
- Entity와 DTO를 반드시 분리
- 예외 처리는 @RestControllerAdvice 활용

## 코딩 컨벤션
- 패키지 구조: com.example.{도메인}.{layer}
- REST API는 /api/v1 prefix 사용
- 테스트는 반드시 작성 (JUnit 5 + MockK)
- 커밋 메시지: Conventional Commits 형식

## 빌드 &amp;amp; 실행
- 빌드: ./gradlew build
- 테스트: ./gradlew test
- 린트: ./gradlew ktlintCheck
- 실행: ./gradlew bootRun

## 절대 하지 말 것
- WebClient나 RestTemplate 사용 금지 (RestClient만 사용)
- var 남용 금지, 타입을 명시적으로 선언
- 테스트 없이 PR 생성 금지&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;CLAUDE.md 스코프 활용:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;파일 위치적용 범위용도
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;~/.claude/CLAUDE.md&lt;/td&gt;
&lt;td&gt;모든 프로젝트&lt;/td&gt;
&lt;td&gt;개인 글로벌 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프로젝트루트/CLAUDE.md&lt;/td&gt;
&lt;td&gt;해당 프로젝트 전체&lt;/td&gt;
&lt;td&gt;팀 공유 컨벤션 (Git 커밋)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;프로젝트루트/.claude/CLAUDE.md&lt;/td&gt;
&lt;td&gt;해당 프로젝트 (로컬)&lt;/td&gt;
&lt;td&gt;개인 로컬 설정 (.gitignore)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.2 Rules 설정 &amp;mdash; 주제별 모듈 지침&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.claude/rules/ 디렉토리에 주제별 규칙 파일을 두면, Claude가 관련 작업 시 자동으로 참조합니다. frontmatter로 경로 스코핑도 가능합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;&amp;lt;!-- .claude/rules/api-design.md --&amp;gt;
---
globs: [&quot;**/controller/**&quot;, &quot;**/api/**&quot;]
---

# API 설계 규칙
- ResponseEntity로 감싸서 반환
- 페이지네이션은 Spring Data의 Pageable 사용
- 400/404/500 에러 응답 형식 통일&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.3 Skills 설정 &amp;mdash; 재사용 가능한 워크플로우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.claude/skills/ 디렉토리에 반복되는 작업 패턴을 정의하면 /skill-name으로 호출할 수 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;&amp;lt;!-- .claude/skills/new-api.md --&amp;gt;
# 새 API 엔드포인트 생성

## 절차
1. Controller 클래스 생성 (또는 기존에 추가)
2. Request/Response DTO 정의
3. Service 인터페이스 및 구현체 작성
4. Repository 생성 (필요 시)
5. 통합 테스트 작성
6. API 문서 업데이트

## 참고 패턴
- 기존 예시: src/main/kotlin/com/example/order/controller/OrderController.kt&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.4 Hooks 설정 &amp;mdash; 자동 품질 게이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hooks는 Claude의 에이전틱 루프 &lt;b&gt;바깥&lt;/b&gt;에서 결정론적으로 실행되는 스크립트입니다. 코드 변경 후 자동으로 린트/빌드를 실행하여 품질을 강제할 수 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;json&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;json&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;// .claude/settings.json
{
  &quot;hooks&quot;: {
    &quot;stop&quot;: [
      {
        &quot;command&quot;: &quot;./gradlew ktlintCheck --quiet&quot;,
        &quot;description&quot;: &quot;코드 스타일 자동 검증&quot;
      }
    ]
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Phase 2: 계획 수립 (Plan Before Code)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리서치/계획과 구현을 반드시 분리하세요.&lt;/b&gt; Claude가 바로 코딩에 뛰어들게 하면, 잘못된 문제를 풀거나 아키텍처가 꼬이는 경우가 빈번합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 Plan Mode 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Shift+Tab 두 번으로 Plan Mode를 활성화합니다. 이 모드에서 Claude는 파일을 읽고 분석할 수 있지만, &lt;b&gt;어떤 파일도 수정하지 않습니다.&lt;/b&gt; 아키텍트 모드라고 생각하면 됩니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# Plan Mode에서의 프롬프트 예시
주문 취소 API를 구현해야 합니다.

요구사항:
- PUT /api/v1/orders/{id}/cancel
- 주문 상태가 PENDING일 때만 취소 가능
- 취소 시 재고 복원 필요
- 취소 사유(reason)를 기록

먼저 기존 OrderController와 OrderService를 분석하고,
구현 계획을 세워주세요. 아직 코드를 작성하지 마세요.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 구조화된 프롬프트 작성 (CIF 원칙)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효과적인 프롬프트는 &lt;b&gt;Context(맥락)&lt;/b&gt;, &lt;b&gt;Intent(의도)&lt;/b&gt;, **Format(형식)**을 포함합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# ❌ 모호한 프롬프트
폼 추가해줘

# ✅ 구조화된 프롬프트
[Context] OrderController.kt에 주문 수정 API가 필요합니다.
[Intent] 기존 createOrder 패턴을 따라서 updateOrder 엔드포인트를 구현해주세요.
[Format]
- PUT /api/v1/orders/{id}
- UpdateOrderRequest DTO 생성 (수량, 배송주소 변경 가능)
- 서비스 레이어에서 변경 감지 및 이벤트 발행
- 통합 테스트 포함
- 기존 OrderControllerTest.kt 패턴 참고&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 검증 기준을 먼저 제시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude에게 &lt;b&gt;스스로 검증할 수 있는 수단&lt;/b&gt;을 제공하면 품질이 극적으로 향상됩니다. 테스트, 빌드 명령, 린트 등이 여기에 해당합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;구현 후 다음을 확인해주세요:
1. ./gradlew test 전체 통과
2. ./gradlew ktlintCheck 통과
3. 기존 테스트가 깨지지 않는지 확인&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Phase 3: 구현&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 작업 단위 분할&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복잡한 기능은 한 번에 구현하지 말고, 검증 가능한 단위로 나누세요.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# 주문 시스템 구현을 단계별로 나눈 예시

Step 1: &quot;Order Entity와 Repository를 만들어주세요. 
         엔티티 생성 후 ./gradlew test로 확인.&quot;

/clear

Step 2: &quot;OrderService를 구현해주세요. 
         주문 생성, 조회, 취소 로직 포함.
         각 메서드에 대한 단위 테스트 작성.&quot;

/clear

Step 3: &quot;OrderController를 구현해주세요.
         기존 UserController.kt 패턴을 따라주세요.
         통합 테스트 작성 후 전체 테스트 실행.&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 /clear를 적극적으로 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새 작업을 시작할 때마다 /clear로 컨텍스트를 초기화하세요.&lt;/b&gt; 컨텍스트가 쌓이면 Claude의 성능이 저하되고, 토큰 소비가 증가하며, 이전 대화의 실수가 반복될 수 있습니다. 컨텍스트 열화(context degradation)는 Claude Code 사용 시 가장 흔한 실패 원인입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# 이렇게 하지 마세요 (한 세션에서 모든 것)
&quot;Entity 만들어줘&quot; &amp;rarr; &quot;Service도 추가&quot; &amp;rarr; &quot;아 그리고 Controller도&quot; &amp;rarr; &quot;테스트도...&quot;

# 이렇게 하세요 (작업 단위별 세션 분리)
[세션 1] Entity + Repository + 테스트 &amp;rarr; /clear
[세션 2] Service + 테스트 &amp;rarr; /clear  
[세션 3] Controller + 통합 테스트 &amp;rarr; /clear&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 기존 코드를 예시로 제공&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code는 프로젝트의 기존 패턴을 보여줄 때 가장 일관된 코드를 생성합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;ProductController를 새로 만들어주세요.
기존 OrderController.kt의 패턴(에러 핸들링, 응답 형식, 페이지네이션)을 
그대로 따라주세요.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.4 병렬 세션 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;독립적인 작업은 여러 Claude Code 세션을 동시에 실행하여 병렬로 처리할 수 있습니다. VS Code 확장을 사용하면 여러 패널에서 동시에 인스턴스를 실행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Writer/Reviewer 패턴:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;세션역할작업
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;세션 A&lt;/td&gt;
&lt;td&gt;Writer&lt;/td&gt;
&lt;td&gt;API 엔드포인트 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 B&lt;/td&gt;
&lt;td&gt;Reviewer&lt;/td&gt;
&lt;td&gt;세션 A의 코드 리뷰 (편향 없이)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Test-First 패턴:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;세션역할작업
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;세션 A&lt;/td&gt;
&lt;td&gt;테스트 작성자&lt;/td&gt;
&lt;td&gt;테스트 케이스 먼저 작성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;세션 B&lt;/td&gt;
&lt;td&gt;구현자&lt;/td&gt;
&lt;td&gt;작성된 테스트를 통과하는 코드 구현&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Phase 4: 품질 검증&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.1 자동 검증 루프&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code가 스스로 검증하도록 구성하면, 사람이 피드백 루프에 개입할 필요가 줄어듭니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;다음 순서로 진행해주세요:
1. OrderCancelService 구현
2. 단위 테스트 작성 및 실행
3. 테스트 실패 시 코드 수정 후 재실행
4. ./gradlew ktlintCheck로 스타일 검증
5. 전체 빌드 ./gradlew build 확인&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.2 MCP 통합으로 시각적 검증&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MCP(Model Context Protocol) 서버를 연결하면 Claude가 브라우저, 콘솔 로그 등을 직접 확인할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Claude in Chrome&lt;/b&gt;: 실제 브라우저에서 UI를 열어 시각적 검증&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Playwright MCP&lt;/b&gt;: 자동화된 브라우저 테스트 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Chrome DevTools MCP&lt;/b&gt;: 콘솔 로그와 네트워크 요청 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4.3 코드 리뷰 자동화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/install-github-app으로 Claude의 PR 자동 리뷰를 설정할 수 있습니다. 사람이 변수명을 지적하는 동안 Claude는 실제 로직 오류와 보안 이슈를 찾아냅니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;yaml&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# claude-code-review.yml
direct_prompt: |
  이 PR을 리뷰하고 버그와 보안 이슈만 보고해주세요.
  간결하게 작성하세요.
  코딩 스타일이나 변수명은 무시하세요.&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Phase 5: Git 워크플로우 &amp;amp; 배포&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.1 커밋과 PR 자동화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code에게 Git 작업을 위임하면 시간을 절약하면서도 일관된 커밋 메시지를 유지할 수 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# 변경사항을 Conventional Commits 형식으로 커밋
지금까지의 변경사항을 적절한 단위로 나눠서 커밋해주세요.
Conventional Commits 형식을 사용하세요.

# PR 생성
이 브랜치의 변경사항으로 PR을 만들어주세요.
- 제목: feat: 주문 취소 API 구현
- 본문에 변경 내용, 테스트 방법, 영향 범위를 포함&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5.2 CI 파이프라인 연동&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 CI/CD 파이프라인에서 비대화형(headless)으로 실행할 수 있습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;# CI에서 자동 코드 수정 (린트 에러 등)
claude -p &quot;린트 에러를 모두 수정해주세요&quot; --allowedTools &quot;Edit,Bash&quot;

# 배치 작업
for issue in $ISSUES; do
  claude -p &quot;이슈 $issue를 해결하고 PR을 생성해주세요&quot;
done&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 원칙 요약&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반드시 지켜야 할 것&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;CLAUDE.md를 꼼꼼히 작성하세요&lt;/b&gt; &amp;mdash; 투자 대비 효과가 가장 큰 단일 작업입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코딩 전에 반드시 계획하세요&lt;/b&gt; &amp;mdash; Plan Mode로 아키텍처를 먼저 확정하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증 수단을 제공하세요&lt;/b&gt; &amp;mdash; 테스트, 린트, 빌드 명령을 Claude에게 알려주세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;/clear를 습관화하세요&lt;/b&gt; &amp;mdash; 작업 전환 시 컨텍스트를 초기화하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기존 패턴을 예시로 보여주세요&lt;/b&gt; &amp;mdash; 새 코드의 일관성이 크게 향상됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작업을 작게 나누세요&lt;/b&gt; &amp;mdash; 한 세션에 한 가지 작업만 집중하세요.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;반드시 피해야 할 것&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Kitchen Sink 세션&lt;/b&gt; &amp;mdash; 한 세션에서 관련 없는 여러 작업을 섞지 마세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모호한 프롬프트&lt;/b&gt; &amp;mdash; &quot;API 만들어줘&quot; 대신 구체적인 스펙을 제공하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검증 없는 수락&lt;/b&gt; &amp;mdash; Claude가 생성한 코드를 반드시 빌드/테스트하세요.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MCP 서버 과다 연결&lt;/b&gt; &amp;mdash; 실제로 사용하는 것만 연결하세요 (4개 이내 권장).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코드 소유권 방기&lt;/b&gt; &amp;mdash; PR에 이름이 올라가는 것은 당신입니다. 최종 책임은 개발자에게 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;권장 워크플로우 치트시트&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #14181f;&quot;&gt;&lt;code&gt;┌─────────────────────────────────────────────────┐
│  1. 인프라 세팅                                    │
│     CLAUDE.md 작성 &amp;rarr; Rules 설정 &amp;rarr; Hooks 구성       │
├─────────────────────────────────────────────────┤
│  2. 계획 수립 (Plan Mode)                          │
│     요구사항 분석 &amp;rarr; 아키텍처 설계 &amp;rarr; 계획 확인         │
├─────────────────────────────────────────────────┤
│  3. 단계별 구현                                    │
│     작업 분할 &amp;rarr; 구현 &amp;rarr; 검증 &amp;rarr; /clear &amp;rarr; 다음 작업    │
├─────────────────────────────────────────────────┤
│  4. 품질 검증                                      │
│     테스트 실행 &amp;rarr; 린트 통과 &amp;rarr; 빌드 확인              │
├─────────────────────────────────────────────────┤
│  5. Git 워크플로우                                  │
│     커밋 &amp;rarr; PR 생성 &amp;rarr; 코드 리뷰 &amp;rarr; 머지               │
└─────────────────────────────────────────────────┘&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://code.claude.com/docs/en/best-practices&quot;&gt;Claude Code 공식 Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.claude.com/en/docs/claude-code/overview&quot;&gt;Claude Code 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hesreallyhim/awesome-claude-code&quot;&gt;awesome-claude-code (커뮤니티 리소스)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>프로그래밍 언어</category>
      <category>Claude</category>
      <category>claudecode</category>
      <category>클로드코드</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/168</guid>
      <comments>https://devoops.tistory.com/168#entry168comment</comments>
      <pubDate>Tue, 24 Feb 2026 00:20:00 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter] Flutter에서 네이버 MAP API 연동 방법</title>
      <link>https://devoops.tistory.com/167</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버지도를 플러터에서 띄울 수 있는 플러그인입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Plug-in which shows naver map on flutter project support Android and iOS.&lt;/p&gt;
&lt;h2 id=&quot;install&quot; data-ke-size=&quot;size26&quot;&gt;Install&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 플러그인은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://docs.ncloud.com/ko/naveropenapi_v3/maps/overview.html&quot;&gt;Naver Cloud PlatForm - map&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 제공하는 map서비스를 Android와 iOS 환경에서 보여주는 플러그인입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Naver cloud platform 에서 콘솔의 AI&amp;middot;Application Service &amp;gt; AI&amp;middot;NAVER API &amp;gt; Application에서 애플리케이션을 등록합니다.&lt;/li&gt;
&lt;li&gt;등록한 애플리케이션을 선택해 Client ID값을 확인하고 변경 화면에서 Maps가 선택되어 있는지 확인한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pubspec.yaml에 plug in dependencies에 작성&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;dependencies:
  naver_map_plugin: ^0.9.6
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id=&quot;warning&quot; data-ke-size=&quot;size23&quot;&gt;Warning&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지도에서 제공하는 기본 컨트롤러가 잘 작동하지 않는 문제 (이유를 찾지 못하고 있음)&lt;/li&gt;
&lt;li&gt;android는 현 위치 버튼만 정상 작동&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;notice-android&quot; data-ke-size=&quot;size23&quot;&gt;NOTICE (Android)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한국어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네이버에서 제공하는 SDK의 경우 안드로이드에서 지도를 표시하기 위해 기본값으로 GLSurfaceView를 사용한다. hot reload시에 naver map SDK의 binary에서 정확하지 않은 이유로 app crash가 발생한다. reload하지 않는 release version 에서는 성능이 더 좋은 GLSurfaceView를 사용하고, 아닌 경우 hot reload가 가능한 TextureView를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;English
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NaverMap SDK use GLSurfaceView as default to flush map view in Android. At hot reload, App crash occurs in binary file of naver map SDK caused by unclear reason. if you build released version, this plug-in use GLSurfaceView for better performance, otherwise TextureView is used to make hot-reload available.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;android-getting-start&quot; data-ke-size=&quot;size26&quot;&gt;ANDROID GETTING START&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 id=&quot;naver-cloud-platform---android--httpsdocsncloudcomkonaveropenapi_v3mapsandroid-sdkv3starthtml&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://docs.ncloud.com/ko/naveropenapi_v3/maps/android-sdk/v3/start.html&quot;&gt;Naver Cloud Platform - Android 시작 가이드&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AndroidManifest.xml에 지정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;manifest&amp;gt;
    &amp;lt;application&amp;gt;
        &amp;lt;meta-data
            android:name=&quot;com.naver.maps.map.CLIENT_ID&quot;
            android:value=&quot;YOUR_CLIENT_ID_HERE&quot; /&amp;gt;
    &amp;lt;/application&amp;gt;
&amp;lt;/manifest&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;naver map에서 현위치탐색 기능을 사용하기 위해서는 AndroidManifest.xml에서 권한을 명시한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;manifest&amp;gt;
    &amp;lt;uses-permission android:name=&quot;android.permission.ACCESS_FINE_LOCATION&quot;/&amp;gt;
&amp;lt;/manifest&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 android API level 23(M) 이상의 경우 동적 권한을 필요로 한다. 다음은 동적권한을 요청하는 예제 코드이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.M) {
    if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 0);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&quot;ios-getting-start&quot; data-ke-size=&quot;size26&quot;&gt;iOS GETTING START&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 id=&quot;naver-cloud-platform---ios--httpsdocsncloudcomkonaveropenapi_v3mapsios-sdkv3starthtml&quot; data-ke-size=&quot;size20&quot;&gt;&lt;a href=&quot;https://docs.ncloud.com/ko/naveropenapi_v3/maps/ios-sdk/v3/start.html&quot;&gt;Naver Cloud Platform - iOS 시작 가이드&lt;/a&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대용량 파일을 받기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://git-lfs.github.com/&quot;&gt;git-lfs&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;설치가 필요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;$ brew install git-lfs
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 git-lfs을 사용하기 위해 다음의 커맨드를 입력해주세요. lfs 사용 설정이 안될 경우 pod를 통한 dependency가 다운로드 되지않습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;$ git lfs install
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;info.plist에 지정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;dict&amp;gt;
  &amp;lt;key&amp;gt;NMFClientId&amp;lt;/key&amp;gt;
  &amp;lt;string&amp;gt;YOUR_CLIENT_ID_HERE&amp;lt;/string&amp;gt;
  &amp;lt;key&amp;gt;io.flutter.embedded_views_preview&amp;lt;/key&amp;gt;
  &amp;lt;true/&amp;gt;
  &amp;lt;key&amp;gt;NSAllowsArbitraryLoads&amp;lt;/key&amp;gt;
  &amp;lt;true/&amp;gt;
&amp;lt;/dict&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;naver map에서 현위치탐색 기능을 사용하기 위해서는 info.plist에서 권한을 명시한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;dict&amp;gt;
    &amp;lt;key&amp;gt;NSLocationAlwaysAndWhenInUseUsageDescription&amp;lt;/key&amp;gt;
	&amp;lt;string&amp;gt;[USAGE PERPOSE]&amp;lt;/string&amp;gt;
	&amp;lt;key&amp;gt;NSLocationAlwaysUsageDescription&amp;lt;/key&amp;gt;
	&amp;lt;string&amp;gt;[USAGE PERPOSE]&amp;lt;/string&amp;gt;
	&amp;lt;key&amp;gt;NSLocationWhenInUseUsageDescription&amp;lt;/key&amp;gt;
	&amp;lt;string&amp;gt;[USAGE PERPOSE]&amp;lt;/string&amp;gt;
&amp;lt;/dict&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 AppDelefate에서 위치 사용권한을 획득하는 예제.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;pre class=&quot;objectivec&quot;&gt;&lt;code&gt;if (CLLocationManager.locationServicesEnabled()) {
    switch CLLocationManager.authorizationStatus() {
    case .denied, .notDetermined, .restricted:
        self.manager.requestAlwaysAuthorization()
        break
    default:
        break
    }
}       
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;샘플 코드&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;import 'package:flutter/material.dart';

import 'package:naver_map_plugin_example/base_map.dart';
import 'package:naver_map_plugin_example/circle_map.dart';
import 'package:naver_map_plugin_example/padding_test.dart';
import 'package:naver_map_plugin_example/marker_map_page.dart';
import 'package:naver_map_plugin_example/path_map.dart';
import 'package:naver_map_plugin_example/polygon_map.dart';
import 'package:naver_map_plugin_example/text_field_page.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() =&amp;gt; _MyAppState();
}

class _MyAppState extends State&amp;lt;MyApp&amp;gt; {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  @override
  _MainPageState createState() =&amp;gt; _MainPageState();
}

class _MainPageState extends State&amp;lt;MainPage&amp;gt; {
  List&amp;lt;String&amp;gt; menuText = [
    '기본 지도 예제',
    '마커 예제',
    '패스 예제',
    '원형 오버레이 예제',
    '컨트롤러 테스트',
    '폴리곤 예제',
    'GLSurface Thread collision test',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        padding: EdgeInsets.all(16),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: menuText
              .map((text) =&amp;gt; GestureDetector(
                    onTap: () =&amp;gt; _onTapMenuItem(text),
                    child: Container(
                      margin: EdgeInsets.symmetric(vertical: 8),
                      padding: EdgeInsets.all(16),
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(6),
                        border: Border.all(color: Colors.indigo),
                      ),
                      child: Text(
                        text,
                        style: TextStyle(
                          color: Colors.indigo,
                          fontSize: 12,
                          fontWeight: FontWeight.w600,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    ),
                  ))
              .toList(),
        ),
      ),
    );
  }

  _onTapMenuItem(String text) {
    final index = menuText.indexOf(text);
    switch (index) {
      case 0:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) =&amp;gt; BaseMapPage(),
            ));
        break;
      case 1:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) =&amp;gt; MarkerMapPage(),
            ));
        break;
      case 2:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) =&amp;gt; PathMapPage(),
            ));
        break;
      case 3:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) =&amp;gt; CircleMapPage(),
            ));
        break;
      case 4:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) =&amp;gt; PaddingTest(),
            ));
        break;
      case 5:
        Navigator.push(
            context,
            MaterialPageRoute(
              builder: (_) =&amp;gt; PolygonMap(),
            ));
        break;
      case 6:
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (_) =&amp;gt; TextFieldPage(),
          ));
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&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;a href=&quot;https://pub.dev/packages/naver_map_plugin&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://pub.dev/packages/naver_map_plugin&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 언어/Flutter</category>
      <category>Flutter</category>
      <category>navermap</category>
      <category>네이버지도</category>
      <category>플러터</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/167</guid>
      <comments>https://devoops.tistory.com/167#entry167comment</comments>
      <pubDate>Mon, 27 Feb 2023 23:10:11 +0900</pubDate>
    </item>
    <item>
      <title>Fiddler와 유사한 프로그램 리스트</title>
      <link>https://devoops.tistory.com/166</link>
      <description>&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Charles:&lt;/b&gt; 웹 개발자용 HTTP 디버깅 프로그램으로, Fiddler와 비슷한 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Wireshark:&lt;/b&gt; 네트워크 패킷 분석 프로그램으로, Fiddler보다 복잡하지만 다양한 프로토콜을 분석할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Postman:&lt;/b&gt; API 개발 및 테스트용 프로그램으로, Fiddler와 달리 API 대상을 직접 테스트할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Burp Suite&lt;/b&gt;: 웹 애플리케이션 보안 테스트 프로그램으로, Fiddler와 비슷한 기능을 제공하며 보안 관련 기능도 제공합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 프로그램마다 다른 점이 있으니, 개인적인 요구에 맞는 프로그램을 선택하시면 됩니다.&lt;/p&gt;</description>
      <category>Burp suite</category>
      <category>Charles</category>
      <category>fiddler</category>
      <category>Postman</category>
      <category>wireshark</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/166</guid>
      <comments>https://devoops.tistory.com/166#entry166comment</comments>
      <pubDate>Sun, 12 Feb 2023 12:32:13 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter 3.0] Flutter 3.0 초기 환경 설정 on Windows</title>
      <link>https://devoops.tistory.com/165</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Flutter SDK 다운로드&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.flutter.dev/get-started/install/windows&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.flutter.dev/get-started/install/windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;최신 릴리즈 버전 다운로드(현재 3.0.1 최신)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccacoe/btrDqUVo1D2/n0BEJYzQo8qHDL1RPJOtjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccacoe/btrDqUVo1D2/n0BEJYzQo8qHDL1RPJOtjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccacoe/btrDqUVo1D2/n0BEJYzQo8qHDL1RPJOtjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fccacoe%2FbtrDqUVo1D2%2Fn0BEJYzQo8qHDL1RPJOtjK%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;695&quot; height=&quot;164&quot; data-origin-width=&quot;1087&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명시적이고 간편한 경로에 압축을 해제합니다.(예: c:\src\flutter)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Flutter 기본 환경변수 PATH 설정&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;C:\src\flutter 기준&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;701&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYQTmR/btrDoVtJhPz/cRo24aBgebqZgnCxTimlf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYQTmR/btrDoVtJhPz/cRo24aBgebqZgnCxTimlf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYQTmR/btrDoVtJhPz/cRo24aBgebqZgnCxTimlf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYQTmR%2FbtrDoVtJhPz%2FcRo24aBgebqZgnCxTimlf1%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;429&quot; height=&quot;492&quot; data-origin-width=&quot;611&quot; data-origin-height=&quot;701&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RA5qR/btrDtgKqaHf/imj6YKAtfwRWedSCVMQHj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RA5qR/btrDtgKqaHf/imj6YKAtfwRWedSCVMQHj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RA5qR/btrDtgKqaHf/imj6YKAtfwRWedSCVMQHj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRA5qR%2FbtrDtgKqaHf%2Fimj6YKAtfwRWedSCVMQHj0%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;428&quot; height=&quot;242&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;701&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOnA1U/btrDnj8SNH4/k0BGT3RKItdu7Lh3cxXKr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOnA1U/btrDnj8SNH4/k0BGT3RKItdu7Lh3cxXKr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOnA1U/btrDnj8SNH4/k0BGT3RKItdu7Lh3cxXKr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOnA1U%2FbtrDnj8SNH4%2Fk0BGT3RKItdu7Lh3cxXKr1%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;425&quot; height=&quot;441&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;701&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;Windows 명령 프롬프트에서 &lt;span style=&quot;background-color: #000000; color: #ffffff;&quot;&gt;flutter --version&lt;/span&gt; 실행해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ffffff; background-color: #000000;&quot;&gt;Flutter 3.0.1&lt;/span&gt; 표시되면 기본 PATH가 잘 설정된 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;115&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba9NYa/btrDkDmH3oi/RgRbC6B6dV5X9zyxyHrvpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba9NYa/btrDkDmH3oi/RgRbC6B6dV5X9zyxyHrvpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba9NYa/btrDkDmH3oi/RgRbC6B6dV5X9zyxyHrvpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba9NYa%2FbtrDkDmH3oi%2FRgRbC6B6dV5X9zyxyHrvpK%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;582&quot; height=&quot;86&quot; data-origin-width=&quot;779&quot; data-origin-height=&quot;115&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;h2 data-ke-size=&quot;size26&quot;&gt;Flutter 개발 환경 준비(for Android)&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Windows 명령 프롬프트에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff;&quot;&gt;flutter doctor&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;실행해보자.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 개발 환경 준비가 잘 되어 있다면 &quot;No issues found!&quot; 메시지를 확인 할 수 있다.&lt;/li&gt;
&lt;li&gt;준비되지 않은 체크 리스트는 해결 방법이 친절하게 제시되니 참고해서 해결하도록 하자&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YexR6/btrDnqAXoSk/6w1kadL7mgeWNML6vApRRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YexR6/btrDnqAXoSk/6w1kadL7mgeWNML6vApRRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YexR6/btrDnqAXoSk/6w1kadL7mgeWNML6vApRRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYexR6%2FbtrDnqAXoSk%2F6w1kadL7mgeWNML6vApRRk%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;606&quot; height=&quot;160&quot; data-origin-width=&quot;966&quot; data-origin-height=&quot;255&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;h2 data-ke-size=&quot;size26&quot;&gt;Flutter Doctor 이슈 해결방법&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Android toolchain - Some Android licenses not accepted&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Android 라이선스만 동의하면 쉽게 해결된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff;&quot;&gt;flutter doctor --android-licenses &lt;/span&gt;그대로 타이핑하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;50&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cps46q/btrDoadDZng/ViYab87GKCY4hfVMxA19t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cps46q/btrDoadDZng/ViYab87GKCY4hfVMxA19t0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cps46q/btrDoadDZng/ViYab87GKCY4hfVMxA19t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcps46q%2FbtrDoadDZng%2FViYab87GKCY4hfVMxA19t0%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;700&quot; height=&quot;50&quot; data-origin-width=&quot;990&quot; data-origin-height=&quot;50&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 언어/Flutter</category>
      <category>flutter 3.0</category>
      <category>flutter3</category>
      <category>플러터3</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/165</guid>
      <comments>https://devoops.tistory.com/165#entry165comment</comments>
      <pubDate>Sun, 29 May 2022 18:19:56 +0900</pubDate>
    </item>
    <item>
      <title>[야외맛집] 양산하얀집가든 미나리삼겹살/묵은지삼겹살</title>
      <link>https://devoops.tistory.com/164</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1635438602959&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;하얀집가든 미나리삼겹살 : 네이버&quot; data-og-description=&quot;육류,고기요리 &amp;middot; 매일 11:00 - 18:00, 야외 바베큐&quot; data-og-host=&quot;m.place.naver.com&quot; data-og-source-url=&quot;http://naver.me/FEJSgjKZ&quot; data-og-url=&quot;https://m.place.naver.com/restaurant/1818384094/home&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d3YYkT/hyL8BMJarZ/DZ1mdcv6DGU0vhvzjmySZK/img.jpg?width=640&amp;amp;height=380&amp;amp;face=0_0_640_380,https://scrap.kakaocdn.net/dn/hzQnW/hyL8A1mv4Y/oEWzjqrB9KWWIJdJIwsCuk/img.jpg?width=640&amp;amp;height=380&amp;amp;face=0_0_640_380&quot;&gt;&lt;a href=&quot;http://naver.me/FEJSgjKZ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://naver.me/FEJSgjKZ&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d3YYkT/hyL8BMJarZ/DZ1mdcv6DGU0vhvzjmySZK/img.jpg?width=640&amp;amp;height=380&amp;amp;face=0_0_640_380,https://scrap.kakaocdn.net/dn/hzQnW/hyL8A1mv4Y/oEWzjqrB9KWWIJdJIwsCuk/img.jpg?width=640&amp;amp;height=380&amp;amp;face=0_0_640_380');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;하얀집가든 미나리삼겹살 : 네이버&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;육류,고기요리 &amp;middot; 매일 11:00 - 18:00, 야외 바베큐&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;m.place.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4608&quot; data-origin-height=&quot;2184&quot; data-filename=&quot;20210923_155100.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdLCVa/btrjb4cYASs/81MwU4SVrtaVRaaSCJXZOk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdLCVa/btrjb4cYASs/81MwU4SVrtaVRaaSCJXZOk/img.jpg&quot; data-alt=&quot;여름에는 수영장 펜션으로&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdLCVa/btrjb4cYASs/81MwU4SVrtaVRaaSCJXZOk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdLCVa%2Fbtrjb4cYASs%2F81MwU4SVrtaVRaaSCJXZOk%2Fimg.jpg&quot; data-origin-width=&quot;4608&quot; data-origin-height=&quot;2184&quot; data-filename=&quot;20210923_155100.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;여름에는 수영장 펜션으로&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4608&quot; data-origin-height=&quot;2184&quot; data-filename=&quot;20210922_180724.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pxJJP/btrjcuoYzdP/NTx6I72ScG5lD5BhqDtsJK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pxJJP/btrjcuoYzdP/NTx6I72ScG5lD5BhqDtsJK/img.jpg&quot; data-alt=&quot;푸짐하죠? ^^&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pxJJP/btrjcuoYzdP/NTx6I72ScG5lD5BhqDtsJK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpxJJP%2FbtrjcuoYzdP%2FNTx6I72ScG5lD5BhqDtsJK%2Fimg.jpg&quot; data-origin-width=&quot;4608&quot; data-origin-height=&quot;2184&quot; data-filename=&quot;20210922_180724.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;푸짐하죠? ^^&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;1908&quot; data-filename=&quot;20210922_185017.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLONMd/btrjeuhrKEh/ujbeLEycBDdh034rPl5Lok/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLONMd/btrjeuhrKEh/ujbeLEycBDdh034rPl5Lok/img.jpg&quot; data-alt=&quot;묵은지와 삼겹살 그리고 버섯 꺄~&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLONMd/btrjeuhrKEh/ujbeLEycBDdh034rPl5Lok/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLONMd%2FbtrjeuhrKEh%2FujbeLEycBDdh034rPl5Lok%2Fimg.jpg&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;1908&quot; data-filename=&quot;20210922_185017.jpg&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;묵은지와 삼겹살 그리고 버섯 꺄~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00043.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SPFul/btrjbzj4Qjx/PdLcrJlO0kg6CKTY9p1kb0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SPFul/btrjbzj4Qjx/PdLcrJlO0kg6CKTY9p1kb0/img.jpg&quot; data-alt=&quot;얼음컵 한가득 쉬원한 생맥주!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SPFul/btrjbzj4Qjx/PdLcrJlO0kg6CKTY9p1kb0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSPFul%2Fbtrjbzj4Qjx%2FPdLcrJlO0kg6CKTY9p1kb0%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00043.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;얼음컵 한가득 쉬원한 생맥주!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00077.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvxnIq/btrjc7fX4bE/120a7KlRuqKnhmQfHvRlDK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvxnIq/btrjc7fX4bE/120a7KlRuqKnhmQfHvRlDK/img.jpg&quot; data-alt=&quot;싱싱합니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvxnIq/btrjc7fX4bE/120a7KlRuqKnhmQfHvRlDK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvxnIq%2Fbtrjc7fX4bE%2F120a7KlRuqKnhmQfHvRlDK%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00077.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;싱싱합니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00158.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5pzjI/btri7RscQJQ/XQTJA3ETiMvAfSP7NtP71k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5pzjI/btri7RscQJQ/XQTJA3ETiMvAfSP7NtP71k/img.jpg&quot; data-alt=&quot;먹고 또 먹고!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5pzjI/btri7RscQJQ/XQTJA3ETiMvAfSP7NtP71k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5pzjI%2Fbtri7RscQJQ%2FXQTJA3ETiMvAfSP7NtP71k%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00158.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;먹고 또 먹고!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00195.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Runth/btrjc69c7at/Lykm6tkNySs3IlHxStoKO0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Runth/btrjc69c7at/Lykm6tkNySs3IlHxStoKO0/img.jpg&quot; data-alt=&quot;고기 먹고, 물놀이 하고, 고기 먹고, 물놀이하고~&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Runth/btrjc69c7at/Lykm6tkNySs3IlHxStoKO0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRunth%2Fbtrjc69c7at%2FLykm6tkNySs3IlHxStoKO0%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00195.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;고기 먹고, 물놀이 하고, 고기 먹고, 물놀이하고~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00234.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7xS6y/btrjc6g42Uf/kqM5cRpni0DKZvW745Qgak/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7xS6y/btrjc6g42Uf/kqM5cRpni0DKZvW745Qgak/img.jpg&quot; data-alt=&quot;자연 만끽~~~&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7xS6y/btrjc6g42Uf/kqM5cRpni0DKZvW745Qgak/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7xS6y%2Fbtrjc6g42Uf%2FkqM5cRpni0DKZvW745Qgak%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00234.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;자연 만끽~~~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00244.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rCLky/btri7RyY9Ux/0Qgb95QMFGRlOLZjetKpvK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rCLky/btri7RyY9Ux/0Qgb95QMFGRlOLZjetKpvK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rCLky/btri7RyY9Ux/0Qgb95QMFGRlOLZjetKpvK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrCLky%2Fbtri7RyY9Ux%2F0Qgb95QMFGRlOLZjetKpvK%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00244.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00278.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5hLxh/btri85KsrcT/ZgiUuPjKdT73IKrE9glN30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5hLxh/btri85KsrcT/ZgiUuPjKdT73IKrE9glN30/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5hLxh/btri85KsrcT/ZgiUuPjKdT73IKrE9glN30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5hLxh%2Fbtri85KsrcT%2FZgiUuPjKdT73IKrE9glN30%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00278.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00293.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tre22/btrjfDFdHiz/1EKmogsJYYNGKCFjf6MJBK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tre22/btrjfDFdHiz/1EKmogsJYYNGKCFjf6MJBK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tre22/btrjfDFdHiz/1EKmogsJYYNGKCFjf6MJBK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ftre22%2FbtrjfDFdHiz%2F1EKmogsJYYNGKCFjf6MJBK%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00293.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00332.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzuCR1/btrjdOHdzIh/kjVIA0GoSQUrUGvJex8jH0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzuCR1/btrjdOHdzIh/kjVIA0GoSQUrUGvJex8jH0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzuCR1/btrjdOHdzIh/kjVIA0GoSQUrUGvJex8jH0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzuCR1%2FbtrjdOHdzIh%2FkjVIA0GoSQUrUGvJex8jH0%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00332.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00515.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wl4dl/btri845RpYz/bTq2jED57EcmXrOgzIoH6k/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wl4dl/btri845RpYz/bTq2jED57EcmXrOgzIoH6k/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wl4dl/btri845RpYz/bTq2jED57EcmXrOgzIoH6k/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwl4dl%2Fbtri845RpYz%2FbTq2jED57EcmXrOgzIoH6k%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00515.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00505.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTx6mS/btri7Sq6ZTE/Cdv0zKqrmpypjok5XETHk0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTx6mS/btri7Sq6ZTE/Cdv0zKqrmpypjok5XETHk0/img.jpg&quot; data-alt=&quot;야옹이들이 한가득~~&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTx6mS/btri7Sq6ZTE/Cdv0zKqrmpypjok5XETHk0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTx6mS%2Fbtri7Sq6ZTE%2FCdv0zKqrmpypjok5XETHk0%2Fimg.jpg&quot; data-origin-width=&quot;4096&quot; data-origin-height=&quot;2304&quot; data-filename=&quot;resized_DSC00505.JPG&quot; data-ke-mobilestyle=&quot;widthOrigin&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;/&gt;&lt;/span&gt;&lt;figcaption&gt;야옹이들이 한가득~~&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>양산묵은지삼겹살</category>
      <category>양산미나리삼겹살</category>
      <category>양산바베큐파티</category>
      <category>양산야외식당</category>
      <category>양산야외파티</category>
      <category>양산하얀집가든</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/164</guid>
      <comments>https://devoops.tistory.com/164#entry164comment</comments>
      <pubDate>Fri, 29 Oct 2021 01:42:00 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 Concept</title>
      <link>https://devoops.tistory.com/157</link>
      <description>&lt;p&gt;&lt;b&gt;Concept의 개념&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 함수 템플릿(또는 클래스 템플릿)은 모든 타입이 아니라 특정 조건을 만족하는 타입에 대해서 동작하게 됨&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;타입이 가져야 하는 조건을 코드로 표현&lt;/span&gt; 한 것&lt;/li&gt;
&lt;li&gt;2000년 중반부터 이야기 되었으나 아직 표준화 되지 않음&lt;/li&gt;
&lt;li&gt;C++20 표준에 추가될 예정&lt;/li&gt;
&lt;li&gt;Concept 문법이 도입될 경우 템플릿 코드에 많은 변화가 있게됨&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610456743009&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

struct Point
{
    int x, y;
};

// 실제 파라미터가 모든 타입이 아닌 연산자 &amp;lt; 가능한 타입에 대해서만 지원하는 템플릿임
template&amp;lt;typename T&amp;gt; T Min(T x, T y)
{
    return y &amp;lt; x ? y : x;
}

int main()
{
    Point p1, p2;
    Min(p1, p2);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1610457283567&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

struct Point
{
    int x, y;
    bool operator&amp;lt;(const Point&amp;amp; p) { return true; }
};

// 1. concept 만들기
template&amp;lt;typename T&amp;gt;
concept bool LessThanComparable = requires(T a, T b)
{
    { a &amp;lt; b }-- &amp;gt; bool;
};

// 2. template 만들때 concept 표기
template&amp;lt;typename T&amp;gt; requires LessThanComparable&amp;lt;T&amp;gt;
T Min(T x, T y)
{
    return y &amp;lt; x ? y : x;
}

// 3. template 만들때 T대신 concept 사용
LessThanComparable Min(LessThanComparable x, LessThanComparable y)
{
    return y &amp;lt; x ? y : x;
}

int main()
{
    Point p1, p2;
    Min(p1, p2);
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>c++20</category>
      <category>Concept</category>
      <category>컨셉</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/157</guid>
      <comments>https://devoops.tistory.com/157#entry157comment</comments>
      <pubDate>Tue, 12 Jan 2021 22:15:18 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 디자인 Typelist</title>
      <link>https://devoops.tistory.com/156</link>
      <description>&lt;p&gt;&lt;b&gt;Typelist&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;값이 아닌 타입의 리스트를 보관하는 데이터 타입&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;템플릿 인자가 1개라도 Typelist를 활용하면 복수의 타입을 만들 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610284541656&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template&amp;lt;typename T, typename U&amp;gt; struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist&amp;lt;T1, NullType&amp;gt;
#define TYPELIST_2(T1, T2) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Nulltype&amp;gt;&amp;gt;
#define TYPELIST_3(T1, T2, T3) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, Nulltype&amp;gt;&amp;gt;&amp;gt;
#define TYPELIST_2(T1, T2, T3, T4) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, Typelist&amp;lt;T4, Nulltype&amp;gt;&amp;gt;&amp;gt;&amp;gt;

template&amp;lt;typename T&amp;gt; class xtuple {};

int main()
{
    xtuple&amp;lt;int&amp;gt; t1;

    Typelist&amp;lt;int, NullType&amp;gt; t1;
    Typelist&amp;lt;int, Typelist&amp;lt;int, NullType&amp;gt;&amp;gt; t2;
    Typelist&amp;lt;int, Typelist&amp;lt;int, Typelist&amp;lt;char, NullType&amp;gt;&amp;gt;&amp;gt; t3;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Typelist Length&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;타입리스트의 요소 수 구하기&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610285316855&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template&amp;lt;typename T, typename U&amp;gt; struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist&amp;lt;T1, NullType&amp;gt;
#define TYPELIST_2(T1, T2) Typelist&amp;lt;T1, Typelist&amp;lt;T2, NullType&amp;gt;&amp;gt;
#define TYPELIST_3(T1, T2, T3) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, NullType&amp;gt;&amp;gt;&amp;gt;
#define TYPELIST_4(T1, T2, T3, T4) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, Typelist&amp;lt;T4, NullType&amp;gt;&amp;gt;&amp;gt;&amp;gt;

// 1. 사용하는 모습을 보고 메인 템플릿 생성
template&amp;lt;typename T&amp;gt; struct Length;

// 2. 갯수를 구할 수 있도록 부분 특수화
template&amp;lt;typename T, typename U&amp;gt; struct Length&amp;lt;Typelist&amp;lt;T, U&amp;gt;&amp;gt;
{
    enum { value = Length&amp;lt;U&amp;gt;::value + 1 };
};

// 3. 재귀를 종료하기 위한 특수화
template&amp;lt;&amp;gt; struct Length&amp;lt;NullType&amp;gt;
{
    enum { value = 0 };
};

template&amp;lt;typename T&amp;gt; void test()
{
    cout &amp;lt;&amp;lt; Length&amp;lt;T&amp;gt;::value &amp;lt;&amp;lt; endl; // 4
}

int main()
{
    test&amp;lt;TYPELIST_4(int, int, double, float)&amp;gt;();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;TypeAt&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610285963073&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template&amp;lt;typename T, typename U&amp;gt; struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist&amp;lt;T1, NullType&amp;gt;
#define TYPELIST_2(T1, T2) Typelist&amp;lt;T1, Typelist&amp;lt;T2, NullType&amp;gt;&amp;gt;
#define TYPELIST_3(T1, T2, T3) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, NullType&amp;gt;&amp;gt;&amp;gt;
#define TYPELIST_4(T1, T2, T3, T4) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, Typelist&amp;lt;T4, NullType&amp;gt;&amp;gt;&amp;gt;&amp;gt;


// Typelist의 N번째 요소의 타입 구하기
// 메인 템플릿
template&amp;lt;typename T, int N&amp;gt; struct TypeAt
{
    //typedef ? type;
};

// 원하는 타입을 구할 수 있도록 부분 특수화
// N == 0
template&amp;lt;typename T, typename U&amp;gt; struct TypeAt&amp;lt;Typelist&amp;lt;T, U&amp;gt;, 0&amp;gt;
{
    typedef T type;
};

// 원하는 타입을 구할 수 있도록 부분 특수화
// N != 0
template&amp;lt;typename T, typename U, int N&amp;gt; struct TypeAt&amp;lt;Typelist&amp;lt;T, U&amp;gt;, N&amp;gt;
{
    typedef typename TypeAt&amp;lt;U, N-1&amp;gt;::type type;
};

template&amp;lt;typename T&amp;gt; void test()
{
    typename TypeAt&amp;lt;T, 0&amp;gt;::type i; // int
    cout &amp;lt;&amp;lt; typeid(i).name() &amp;lt;&amp;lt; endl;

    typename TypeAt&amp;lt;T, 1&amp;gt;::type c; // char
    cout &amp;lt;&amp;lt; typeid(c).name() &amp;lt;&amp;lt; endl;

    typename TypeAt&amp;lt;T, 2&amp;gt;::type d; // double
    cout &amp;lt;&amp;lt; typeid(d).name() &amp;lt;&amp;lt; endl;

    typename TypeAt&amp;lt;T, 3&amp;gt;::type l; // long
    cout &amp;lt;&amp;lt; typeid(l).name() &amp;lt;&amp;lt; endl;
}

int main()
{
    test&amp;lt;TYPELIST_4(int, char, double, long)&amp;gt;();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Append&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610289150639&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template&amp;lt;typename T, typename U&amp;gt; struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist&amp;lt;T1, NullType&amp;gt;
#define TYPELIST_2(T1, T2) Typelist&amp;lt;T1, Typelist&amp;lt;T2, NullType&amp;gt;&amp;gt;
#define TYPELIST_3(T1, T2, T3) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, NullType&amp;gt;&amp;gt;&amp;gt;
#define TYPELIST_4(T1, T2, T3, T4) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, Typelist&amp;lt;T4, NullType&amp;gt;&amp;gt;&amp;gt;&amp;gt;

// Typelist 끝에 타입 추가하기
template&amp;lt;typename TL, typename T&amp;gt; struct Append;

// TL T
// 1. NullType, NullType =&amp;gt; NullType
template&amp;lt;&amp;gt; struct Append&amp;lt;NullType, NullType&amp;gt;
{
    typedef NullType type;
};

// 2. NullType, 임의의 타입 =&amp;gt; Typelist&amp;lt;임의의 타입, NullType&amp;gt;
template&amp;lt;typename T&amp;gt; struct Append&amp;lt;NullType, T&amp;gt;
{
    typedef Typelist&amp;lt;T, NullType&amp;gt; type;
};

// 3. NullType, Typelist&amp;lt;Head, Tail&amp;gt; = Typelist&amp;lt;Head, Tail&amp;gt;
template&amp;lt;typename Head, typename Tail&amp;gt; struct Append&amp;lt;NullType, Typelist&amp;lt;Head, Tail&amp;gt;&amp;gt;
{
    typedef Typelist&amp;lt;Head, Tail&amp;gt; type;
};

// 4. Typelist&amp;lt;Head, Tail&amp;gt;, NullType =&amp;gt; Typelist&amp;lt;Head, Tail&amp;gt;
template&amp;lt;typename Head, typename Tail&amp;gt; struct Append&amp;lt;Typelist&amp;lt;Head, Tail&amp;gt;, NullType&amp;gt;
{
    typedef Typelist&amp;lt;Head, Tail&amp;gt; type;
};

// 5. Typelist&amp;lt;Head, Tail&amp;gt;, 임의의 타입 =&amp;gt; Typelist&amp;lt;Head, Append&amp;lt;Tail, T&amp;gt;::type&amp;gt;
template&amp;lt;typename Head, typename Tail, typename T&amp;gt; struct Append&amp;lt;Typelist&amp;lt;Head, Tail&amp;gt;, T&amp;gt;
{
    typedef Typelist&amp;lt;Head, typename Append&amp;lt;Tail, T&amp;gt;::type&amp;gt; type;
};

template&amp;lt;typename T&amp;gt; void test()
{
    typename Append&amp;lt;T, int&amp;gt;::type t1;
    cout &amp;lt;&amp;lt; typeid(t1).name() &amp;lt;&amp;lt; endl; // int, char, double, int, NullType
}

int main()
{
    test&amp;lt;TYPELIST_3(int, char, double)&amp;gt;();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Typelist 예제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610290288377&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 값을 보관하지 않음
// 타입 2개를 보관함
template&amp;lt;typename T, typename U&amp;gt; struct Typelist
{
    typedef T Head;
    typedef U Tail;
};

struct NullType {};

// 매크로 도입
#define TYPELIST_1(T1) Typelist&amp;lt;T1, NullType&amp;gt;
#define TYPELIST_2(T1, T2) Typelist&amp;lt;T1, Typelist&amp;lt;T2, NullType&amp;gt;&amp;gt;
#define TYPELIST_3(T1, T2, T3) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, NullType&amp;gt;&amp;gt;&amp;gt;
#define TYPELIST_4(T1, T2, T3, T4) Typelist&amp;lt;T1, Typelist&amp;lt;T2, Typelist&amp;lt;T3, Typelist&amp;lt;T4, NullType&amp;gt;&amp;gt;&amp;gt;&amp;gt;

// Holder : 임의 타입의 data 1개 보관
template&amp;lt;typename T&amp;gt; struct Holder
{
    T value;
};

// GenScatterHierachy =&amp;gt; MakeCode
template&amp;lt;typename T, template&amp;lt;typename&amp;gt; class Unit&amp;gt; 
class MakeCode : public Unit&amp;lt;T&amp;gt;
{
};

template&amp;lt;template&amp;lt;typename&amp;gt; class Unit&amp;gt; 
class MakeCode&amp;lt;NullType, Unit&amp;gt;
{
};

template&amp;lt;typename Head,             //            , Holder&amp;lt;double&amp;gt;,     empty 
    typename Tail,                  // Holder&amp;lt;int&amp;gt;, MakeCode&amp;lt;double, Unit&amp;gt;, MakeCode&amp;lt;NullType&amp;gt;
    template&amp;lt;typename&amp;gt; class Unit&amp;gt;  // MakeCode&amp;lt;int, Unit&amp;gt;, MakeCode&amp;lt;Typelist&amp;lt;double, NullType&amp;gt;, Unit
    
class MakeCode&amp;lt;Typelist&amp;lt;Head, Tail&amp;gt;, Unit&amp;gt; : public MakeCode&amp;lt;Head, Unit&amp;gt;, public MakeCode&amp;lt;Tail, Unit&amp;gt;
{
    // int value;
    // double value;
};

int main()
{
    // MakeCode의 1번째 인자가 Typelist일때
    MakeCode&amp;lt;TYPELIST_2(int, double), Holder&amp;gt; mc1;  // 기반 클래스 Holder&amp;lt;int&amp;gt;
                                // Holder&amp;lt;int&amp;gt;와 메모리 모양이 동일
    MakeCode&amp;lt;double, Holder&amp;gt; mc2; // Holder&amp;lt;double&amp;gt;
    MakeCode&amp;lt;NullType, Holder&amp;gt; mc3; // Empty
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>Typelist</category>
      <category>Typelist Append</category>
      <category>Typelist Length</category>
      <category>Typelist TypeAt</category>
      <category>타입리스트</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/156</guid>
      <comments>https://devoops.tistory.com/156#entry156comment</comments>
      <pubDate>Sun, 10 Jan 2021 22:39:32 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 디자인 Member Detect IDioms</title>
      <link>https://devoops.tistory.com/155</link>
      <description>&lt;p&gt;&lt;b&gt;Member Detect IDioms&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;클래스의 멤버 타입 존재 여부 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;클래스의 멤버 함수 존재 여부 확인&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610281614775&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//컴파일 타임의 함수 시그니처에 대한 특성만 활용하는 특성을 이용하는 기법

// 함수 시그니처만 사용함으로 구현부가 없어도 괜찮음
char foo(int a);
short foo(double d);

int main()
{
    int n = 10;

    cout &amp;lt;&amp;lt; sizeof(n) &amp;lt;&amp;lt; endl; // 4
    //cout &amp;lt;&amp;lt; sizeof(foo) &amp;lt;&amp;lt; endl; // Error
    cout &amp;lt;&amp;lt; sizeof(foo(3)) &amp;lt;&amp;lt; endl; // 1
    cout &amp;lt;&amp;lt; sizeof(foo(3.3)) &amp;lt;&amp;lt; endl; // 2
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1610282982075&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;

// 멤버 타입을 가진 데이터용 템플릿(반환값이 char로 1바이트)
template&amp;lt;typename T&amp;gt; 
char check(typename T::value_type* a);

// 멤버 타입이 없는 데이터용 템플릿(반환값이 short로 2바이트)
template&amp;lt;typename T&amp;gt;
short check(...);

// 멤버 타입이 없는 데이터
struct NoValueType
{
};
// 멤버 타입이 있는 데이터
struct HasValueType
{
    typedef int value_type;
};

// 멤버 타입 존재를 여부 확인 함수
template&amp;lt;typename T&amp;gt;
struct has_value_type
{
    // 반환값이 char(1바이트)일때는 true, short(2바이트)일때는 false
    static constexpr bool value = (sizeof(check&amp;lt;T&amp;gt;(0)) == 1); 
};

int main()
{
    cout &amp;lt;&amp;lt; has_value_type&amp;lt;HasValueType&amp;gt;::value &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; has_value_type&amp;lt;NoValueType&amp;gt;::value &amp;lt;&amp;lt; endl;

    HasValueType t1;
    cout &amp;lt;&amp;lt; sizeof(check&amp;lt;HasValueType&amp;gt;(0)) &amp;lt;&amp;lt; endl;
    NoValueType t2;
    cout &amp;lt;&amp;lt; sizeof(check&amp;lt;NoValueType&amp;gt;(0)) &amp;lt;&amp;lt; endl;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1610283391539&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;

// 멤버함수가 존재할 경우 
template&amp;lt;typename T&amp;gt; 
char check(decltype(T().resize(0))* a);

// 멤버함수가 존재하지 않을 경우
template&amp;lt;typename T&amp;gt;
short check(...);

// 멤버함수 존재 체크
template&amp;lt;typename T&amp;gt;
struct has_resize
{
    static constexpr bool value = (sizeof(check&amp;lt;T&amp;gt;(0)) == 1); 
};

int main()
{
    // vector는 resize가 있으므로 true 리턴
    cout &amp;lt;&amp;lt; has_resize&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;::value &amp;lt;&amp;lt; endl;
    
    // array는 resize가 없으므로 false 리턴
    cout &amp;lt;&amp;lt; has_resize&amp;lt;array&amp;lt;int, 10&amp;gt;&amp;gt;::value &amp;lt;&amp;lt; endl;
}
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>idioms</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/155</guid>
      <comments>https://devoops.tistory.com/155#entry155comment</comments>
      <pubDate>Sun, 10 Jan 2021 21:57:33 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 디자인  SFINAE(Substitution Failure Is Not An Error)</title>
      <link>https://devoops.tistory.com/154</link>
      <description>&lt;p&gt;&lt;b&gt;함수 찾는 순서&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1순위&amp;nbsp;정확한&amp;nbsp;매칭(exactly&amp;nbsp;matching)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;2순위 템플릿(template)&lt;/li&gt;
&lt;li&gt;3순위 가변 인자(variable argument)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610204216461&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt;
// 2순위 템플릿(template)
void foo(T t) { cout &amp;lt;&amp;lt; &quot;T&quot; &amp;lt;&amp;lt; endl; }
// 1순위 정확한 매칭(exactly matching)
void foo(int n) { cout &amp;lt;&amp;lt; &quot;int&quot; &amp;lt;&amp;lt; endl; }
// 3순위 가변 인자(variable argument)
void foo(...) { cout &amp;lt;&amp;lt; &quot;...&quot; &amp;lt;&amp;lt; endl; }

int main()
{
    foo(3);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;SFINAE&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;S&lt;/span&gt;ubstitution &lt;span style=&quot;color: #ee2323;&quot;&gt;F&lt;/span&gt;ailure&lt;span style=&quot;color: #ee2323;&quot;&gt; I&lt;/span&gt;s &lt;span style=&quot;color: #ee2323;&quot;&gt;N&lt;/span&gt;ot &lt;span style=&quot;color: #ee2323;&quot;&gt;A&lt;/span&gt;n &lt;span style=&quot;color: #ee2323;&quot;&gt;E&lt;/span&gt;rror&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 템플릿을 사용시 T의 타입이 결정되고 함수를 생성(Instantiation)하려고 할때 리턴 타입이나 함수 인자등에서 치환에 실패하면 컴파일 에러가 아니라, 함수 후보군에서 제외함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;동일한 이름의 다른 함수가 있다면 다른 함수를 사용하게 됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610271447198&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt;
typename T::type foo(T t) 
{ 
    cout &amp;lt;&amp;lt; &quot;T&quot; &amp;lt;&amp;lt; endl; return 0; 
}

void foo(...) 
{ 
    cout &amp;lt;&amp;lt; &quot;...&quot; &amp;lt;&amp;lt; endl; 
}

int main()
{
    // 가변인자 함수보다 템플릿 함수가 우선순위가 높아서 먼저 참조하게 되지만 리턴 타입에서 
    // int 타입::type은 존재하지 않으므로 만족할 수 없으므로 후보군에서 제외되고 가변인자 버전의 함수가 사용됨
    foo(3); // T
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;enable_if&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;c++표준에서 지원하는 도구&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;1번째 인자가 true일 경우만 type이 정의됨&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;enable_if&amp;lt;true, int&amp;gt;::type&amp;nbsp; -&amp;gt; int&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;enable_if&amp;lt;true&amp;gt;::type -&amp;gt; void&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;enable_if&amp;lt;&lt;span style=&quot;color: #ee2323;&quot;&gt;false&lt;/span&gt;, int&amp;gt;::type -&amp;gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;error&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;enable_if&amp;lt;&lt;span style=&quot;color: #ee2323;&quot;&gt;false&lt;/span&gt;&amp;gt;::type -&amp;gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;error&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610272045021&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;bool b, typename T = void&amp;gt; struct enable_if
{
};

template&amp;lt;typename T&amp;gt; struct enable_if&amp;lt;true, T&amp;gt;
{
    typedef T type;
};

int main()
{
    //enable_if&amp;lt;true, int&amp;gt;::type t0; // 타입이 int로 결정
    //enable_if&amp;lt;true&amp;gt;::type t1; // 타입이 void로 결정
    //enable_if&amp;lt;false, int&amp;gt;::type t2; // 타입이 없어서 error
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;enable_if 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;정수일때만 동작하는 함수를 만들고 싶을때&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;static_assert&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;처리하게 되면 조건을 만족하지 않을 경우 컴파일 에러&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;enable_if&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;SFINAE 특성을 활용한 방법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;조건을 만족하지 않으면 함수를 생성하지 않고 다른 후보가 있다면 사용함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;확장성 유리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610272488358&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 정수일때만 함수 코드를 생성하고 싶음
template&amp;lt;typename T&amp;gt;
typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt;::value, int&amp;gt;::type
foo(T a)
{
    cout &amp;lt;&amp;lt; &quot;T&quot; &amp;lt;&amp;lt; endl;

    return 0;
}

void foo(...)
{
    cout &amp;lt;&amp;lt; &quot;not integer&quot; &amp;lt;&amp;lt; endl;
}

int main()
{
    foo(2.3);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;enable_if 위치&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 리턴 타입&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 인자 타입 -&amp;gt; 생성자에서 주로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;템플릿 인자 -&amp;gt; 함수 자체의 모양이 단순해 보이는 장점 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610273652365&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 함수 리턴 타입 위치
template&amp;lt;typename T&amp;gt;
typename enable_if&amp;lt;is_integral&amp;lt;T&amp;gt;::value, int&amp;gt;::type
foo(T a)
{
    cout &amp;lt;&amp;lt; &quot;T&quot; &amp;lt;&amp;lt; endl;

    return 0;
}

// 함수 인자 타입 위치(리턴 타입이 없는 생성자에서 주로 사용)
template&amp;lt;typename T&amp;gt;
void foo(T a, 
    typename enable_if&amp;lt;
    is_integral&amp;lt;T&amp;gt;::value&amp;gt;::type* = nullptr)
{
    cout &amp;lt;&amp;lt; &quot;T&quot; &amp;lt;&amp;lt; endl;
}

// 템플릿 인자(함수 자체의 원형이 최대한 유지됨으로 간결해 보이는 장점)
template&amp;lt;typename T, 
    typename enable_if&amp;lt;
    is_integral&amp;lt;T&amp;gt;::value&amp;gt;::type* = nullptr&amp;gt;
void foo(T a)
{
    cout &amp;lt;&amp;lt; &quot;T&quot; &amp;lt;&amp;lt; endl;
}

// 모두 만족하지 않을때 호출
void foo(...)
{
    cout &amp;lt;&amp;lt; &quot;not integer&quot; &amp;lt;&amp;lt; endl;
}

int main()
{
    foo(2); // 템플릿 함수 호출(현재 예제코드는 3개의 템플릿이 만족함으로 에러 발생함)
    foo(2.3); // foo(...) 호출
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;타입의 종류에 따라 다르게 동작하는 함수 생성 방법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;type_traits(is_pointer) + if constexpr // C++17에서만 가능&lt;/li&gt;
&lt;li&gt;type_traits + 함수 오버로딩(false_type, true_type)
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;디스패치 함수 1개 더 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;type_traits + enable_if&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610274236036&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// C++17이상 가능 if constexpr 사용 방법

#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; void printv(const T&amp;amp; v)
{
    if constexpr(is_pointer&amp;lt;T&amp;gt;::value)
        cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot;:&quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
    else
        cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; endl;
}

int main()
{
    int n = 0;
    printv(n);
    printv(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1610274606486&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// type_traits + 함수 오버로딩(false_type, true_type)

#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt;
void printv_imp(const T&amp;amp; v, true_type)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot;:&quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
}

template&amp;lt;typename T&amp;gt;
void printv_imp(const T&amp;amp; v, false_type)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot;:&quot; &amp;lt;&amp;lt; endl;
}

template&amp;lt;typename T&amp;gt; void printv(const T&amp;amp; v)
{
    printv_imp(v, is_pointer&amp;lt;T&amp;gt;());
}

int main()
{
    int n = 0;
    printv(n);
    printv(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1610274811139&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// type_traits + enable_if 사용 방법

#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; 
typename enable_if&amp;lt;is_pointer&amp;lt;T&amp;gt;::value&amp;gt;::type 
printv(const T&amp;amp; v)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot;:&quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
}

template&amp;lt;typename T&amp;gt; 
typename enable_if&amp;lt;!is_pointer&amp;lt;T&amp;gt;::value&amp;gt;::type
printv(const T&amp;amp; v)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot;:&quot; &amp;lt;&amp;lt; endl;
}

int main()
{
    int n = 0;
    printv(n);
    printv(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>enable_if</category>
      <category>sfinae</category>
      <category>static_assert</category>
      <category>템플릿 디자인</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/154</guid>
      <comments>https://devoops.tistory.com/154#entry154comment</comments>
      <pubDate>Sun, 10 Jan 2021 18:39:56 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 디자인 단위 전략(Policy-Based Design)</title>
      <link>https://devoops.tistory.com/153</link>
      <description>&lt;p&gt;&lt;b&gt;Policy Based Design&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;클래스가 사용하는 정책을 템플릿 인자를 통해서 교체 할 수 있게 만드는 디자인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;성능 저하 없이 정책을 교체 할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;대부분의 정책은 담은 &quot;단위 전략 클래스&quot;는 지켜야 하는 규칙이 있음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;규칙을 표현하는 코딩 방식은 없음(인터페이스 사용시 가상 함수이므로 약간의 오버헤드 발생), C++20 concept 문법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;우리가 만든 동기화 정책클래스는 &quot;lock/unlock&quot; 함수가 필요함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;템플릿 기반 라이브러리, 특히 STL에서 널리 사용되는 디자인 기법&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610201777437&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 1개의 클래스로 정책 템플릿 인자를 통해서 다르게 구현 할 수 있도록 디자인
template&amp;lt;typename T, typename ThreadModel&amp;gt; class List
{
    ThreadModel tm;
public:
    void push_front(const T&amp;amp; a)
    {
        tm.lock();
        // 구현부 코드
        tm.unlock();
    }
};

// 싱글 쓰레드 기반 환경용
class NoLock
{
public:
    inline void Lock() {};
    inline void Unlock() {}
};

// 멀티 쓰레드 기반 환경용
class MutexLock
{
public:
    inline void Lock() {};
    inline void Unlock() {}
};

// 환경에 따라서 클래스 생성 시 전략을 선택 할 수 있음
// 싱글 쓰레드용 생성
//List&amp;lt;int, NoLock&amp;gt; s;
// 멀티 쓰레드용 생성
List&amp;lt;int, MutexLock&amp;gt; s;

int main()
{
    s.push_front(10);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;STL allocator&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;C++에서 메모리 할당 방법은 다양함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;new, malloc, calloc, win32 api, linux system call&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;STL에서는 각 데이터 컨테이너의 템플릿 인자로 메모리 할당 방식에 대한 전략을 선택할 수 있도록 지원함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610202497564&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// STL의 Vector 생각
// 메모리 할당기
template&amp;lt;typename T&amp;gt; class allocator
{
public:
    T* allocate() {}
    void deallocate() {}
};

template&amp;lt;typename T, typename Ax = allocator&amp;lt;T&amp;gt;&amp;gt; class vector
{
    T* buff;
    Ax ax;
public:
    void resize(int n)
    {
        // 버퍼 재할당이 필요하다면 어떻게 할까요?
        // new, malloc, calloc, win32 api, linux system call
        T* p = ax.allocate(n);
        ax.deallocate(p);
    }
};

int main()
{
    vector&amp;lt;int, MyAlloc&amp;lt;int&amp;gt;&amp;gt; v(10);
    v.resize(20);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;rebind&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610203729712&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; class allocator
{
public:
    T* allocate(int sz) { return new T[sz]; }
    void deallocate(T* p) { delete[] p; }

    template&amp;lt;typename U&amp;gt; struct rebind
    {
        typename allocator&amp;lt;U&amp;gt; other;
    };
};

template&amp;lt;typename T, typename Ax = allocator&amp;lt;T&amp;gt; &amp;gt; class list
{
    struct NODE
    {
        T data;
        NODE* next, * prev;
    };
    //Ax ax; // allocator&amp;lt;int&amp;gt;
    //allocator&amp;lt;int&amp;gt;::rebind&amp;lt;NODE&amp;gt;::other ax; // allocator&amp;lt;NODE&amp;gt; ax;
    typename Ax::template rebind&amp;lt;NODE&amp;gt;::other ax; // allocator&amp;lt;NODE&amp;gt; ax;
public:
    void push_front(const T&amp;amp; a)
    {
        ax.allocate(1);
    }
};

int main()
{
    list&amp;lt;int&amp;gt; s;
    s.push_front(10);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>allocator</category>
      <category>C++</category>
      <category>Policy-Based Design</category>
      <category>rebind</category>
      <category>STL</category>
      <category>단위 전략 디자인</category>
      <category>멀티 쓰레드</category>
      <category>메모리 할당 예제</category>
      <category>싱글 쓰레드</category>
      <category>템플릿 인자 전략</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/153</guid>
      <comments>https://devoops.tistory.com/153#entry153comment</comments>
      <pubDate>Sat, 9 Jan 2021 23:17:18 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 디자인 패턴 CRTP 활용</title>
      <link>https://devoops.tistory.com/152</link>
      <description>&lt;p&gt;&lt;b&gt;CRTP 활용한 싱글톤(Singleton) 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤: 하나의 객체만 생성 할 수 있게 만드는 디자인 패턴
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;private 생성자&lt;/li&gt;
&lt;li&gt;복사와 대입 금지&lt;/li&gt;
&lt;li&gt;하나의 객체를 만들어서 리턴하는 static 멤버 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;단일 Singletone 패턴 클래스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610029628544&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

class Cursor
{
private:
    Cursor() {}
public:
    Cursor(const Cursor&amp;amp; c) = delete;
    void operator=(const Cursor&amp;amp; c) = delete;

    static Cursor&amp;amp; getInstance()
    {
        static Cursor instance;
        return instance;
    }

};

int main()
{
    Cursor&amp;amp; c1 = Cursor::getInstance();
    Cursor&amp;amp; c2 = Cursor::getInstance();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;CRTP 패턴 Singleton 패턴 클래스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610031547122&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt;
class Singleton
{
protected:
    Singleton() {}
public:
    Singleton(const Singleton&amp;amp; c) = delete;
    void operator=(const Singleton&amp;amp; c) = delete;

    static T&amp;amp; getInstance()
    {
        static T instance;
        return instance;
    }
};

class Mouse : public Singleton&amp;lt;Mouse&amp;gt;
{
};

int main()
{
    Mouse&amp;amp; m1 = Mouse::getInstance();
    Mouse&amp;amp; m2 = Mouse::getInstance();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;CRTP 활용한 Unique한 기반 클래스 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기반 클래스의 static memeber data는 모든 파생 클래스에 의해 공유됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;파생 클래스 별로 다른 static member data가 필요한 경우, 서로 다른 기반 클래스를 사용해야 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;CRTP를 사용하면 모든 파생 클래스 별로 다른 타입의 기반 클래스를 만들 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;static 멤버 데이터를 관리하는 단일 클래스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610031822559&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

class Object
{
public:
    static int cnt;

    Object() { ++cnt; }
    ~Object() { --cnt; }

    static int getCount() { return cnt; }
};
int Object::cnt = 0;

int main()
{
    Object c1, c2;
    cout &amp;lt;&amp;lt; c1.getCount() &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;static 멤버 데이터를 관리하는 유일한 기반 클래스&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1610032324714&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt;
class Object
{
public:
    static int cnt;

    Object() { ++cnt; }
    ~Object() { --cnt; }

    static int getCount() { return cnt; }
};
template&amp;lt;typename T&amp;gt; int Object&amp;lt;T&amp;gt;::cnt = 0;

class Mouse : public Object&amp;lt;Mouse&amp;gt;
{

};

class Keyboard : public Object&amp;lt;Keyboard&amp;gt;
{

};

int main()
{
    Mouse m1, m2;
    Keyboard k1, k2;
    cout &amp;lt;&amp;lt; m1.getCount() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; k1.getCount() &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>CRTP</category>
      <category>CRTP Singleton</category>
      <category>template</category>
      <category>템플릿</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/152</guid>
      <comments>https://devoops.tistory.com/152#entry152comment</comments>
      <pubDate>Fri, 8 Jan 2021 00:13:19 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 디자인 패턴 CRTP(Curiously Recurring Template Pattern) 패턴</title>
      <link>https://devoops.tistory.com/151</link>
      <description>&lt;p&gt;&lt;b&gt;CRTP(Cruiously Recurring Template Pattern) 활용&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기반 클래스에서 파생 클래스의 이름을 사용할 수 있게 하는 기법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;파생 클래스를 만들때 기반 클래스의 템플릿 인자로 파생 클래스 이름을 전달&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;기준 코드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 함수 호출 시 기반 클래스의 OnClick 함수가 호출됨&lt;/li&gt;
&lt;li&gt;파생 클래스의 OnClick 함수를 호출하기 위해서는?&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610028624158&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

class Window
{
public:
    void msgLoop()
    {
        OnClick();
    }
    void OnClick() { cout &amp;lt;&amp;lt; &quot;Window OnClick&quot; &amp;lt;&amp;lt; endl; }
};

class FrameWindow : public Window
{
public:
    void OnClick() { cout &amp;lt;&amp;lt; &quot;FrameWindow OnClick&quot; &amp;lt;&amp;lt; endl; }
};

int main()
{
    FrameWindow fw;
    fw.msgLoop(); // OUTPUT : Window OnClick
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;구현 코드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;비 가상 함수(Non virtual function)를 가상 함수 처럼 동작하게 함&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;파생 클래스를 만들때 기반 클래스의 템플릿 인자로 파생 클래스 이름을 전달
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;this 포인터를 파생 클래스 타입으로 캐스팅 후 함 수 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610028375248&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt;
class Window
{
public:
    void msgLoop()
    {
        // this 포인터를 파생 클래스인 T 타입으로 캐스팅 후 호출    
        static_cast&amp;lt;T*&amp;gt;(this)-&amp;gt;OnClick();
    }
    //가상함수로 만들면 가상함수 테이블이 관리됨
    void OnClick() { cout &amp;lt;&amp;lt; &quot;Window OnClick&quot; &amp;lt;&amp;lt; endl; }
};

class FrameWindow : public Window&amp;lt;FrameWindow&amp;gt;
{
public:
    void OnClick() { cout &amp;lt;&amp;lt; &quot;FrameWindow OnClick&quot; &amp;lt;&amp;lt; endl; }
};

int main()
{
    FrameWindow fw;
    fw.msgLoop(); // OUTPUT : FrameWindow OnClick
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>CRTP</category>
      <category>기반 클래스</category>
      <category>파생 클래스</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/151</guid>
      <comments>https://devoops.tistory.com/151#entry151comment</comments>
      <pubDate>Thu, 7 Jan 2021 23:17:50 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 패턴 Thin template, 코드 메모리 최적화 기법</title>
      <link>https://devoops.tistory.com/150</link>
      <description>&lt;p&gt;&lt;b&gt;thin template&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;템플릿의 단점 중 한가지는 코드 메모리의 증가&lt;/li&gt;
&lt;li&gt;모바일등 메모리가 부족한 환경에서 사용할 수 있는 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;기준 코드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;4개의 함수 구성 * 3개의 타입 사용 = 총 12개의 함수 생성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610026184301&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; class Vector
{
    T* buff;
    int sz;
public:
    int size() const {}
    bool empty() const {}
    void push_front(const T&amp;amp; a) {}
    T&amp;amp; front() {}
};

int main()
{
    Vector&amp;lt;int&amp;gt; v1;
    Vector&amp;lt;short&amp;gt; v2;
    Vector&amp;lt;double&amp;gt; v3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;T를 사용하지 않는 모든 멤버를 기반클래스에 정의하고 상속받아서 구현&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;2개의 함수 구성 * 3개의 타입 사용 + 기반 클래스 함수 2개 = 총 8개의 함수 생성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610026362648&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

class VectorBase
{
protected:
    int sz;
public:
    int size() const {}
    bool empty() const {}
};

template&amp;lt;typename T&amp;gt; class Vector : public VectorBase
{
    T* buff;
public:
    void push_front(const T&amp;amp; a) {}
    T&amp;amp; front() {}
};

int main()
{
    Vector&amp;lt;int&amp;gt; v1;
    Vector&amp;lt;short&amp;gt; v2;
    Vector&amp;lt;double&amp;gt; v3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;모든 멤버를 기반 클래스로 구현&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;모든 T는 void*로 변경&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;void*를 바로 사용하면 캐스팅이 불편함으로 캐스팅을 책임지는 파생 클래스를 템플릿으로 제공&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610026759544&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

class VectorBase
{
protected:
    void* buff;
    int sz;
public:
    int size() const {}
    bool empty() const {}
    void push_front(const void* a) {}
    void* front() {}
};

// void*를 바로 사용하면 캐스팅의 불편함이 있음
// 캐스팅을 책임지는 파생 클래스를 템플릿으로 제공
// 캐스팅만 책임지는 함수는 inline로 치환하면 함수화 되지 않음
template&amp;lt;typename T&amp;gt; class Vector : public VectorBase
{
public:
    inline void push_front(const T&amp;amp; a) { VectorBase::push_front(static_cast&amp;lt;void*&amp;gt;(a)) }
    inline T&amp;amp; front() { return static_cast&amp;lt;T&amp;amp;&amp;gt;(VectorBase::front()); }
};

int main()
{
    Vector&amp;lt;int&amp;gt; v1;
    Vector&amp;lt;short&amp;gt; v2;
    Vector&amp;lt;double&amp;gt; v3;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기반 클래스 멤버를 직접 호출 방지를 위해 private 상속으로 변경&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1610026982494&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

class VectorBase
{
protected:
    void* buff;
    int sz;
public:
    int size() const {}
    bool empty() const {}
    void push_front(const void* a) {}
    void* front() {}
};

// void*를 바로 사용하면 캐스팅의 불편함이 있음
// 캐스팅을 책임지는 파생 클래스를 템플릿으로 제공
template&amp;lt;typename T&amp;gt; class Vector : private VectorBase
{
public:
    int size() const { return VectorBase::size(); }
    bool empty() const { return VectorBase::empty(); }
    inline void push_front(const T&amp;amp; a) { VectorBase::push_front(static_cast&amp;lt;void*&amp;gt;(a)); }
    inline T&amp;amp; front() { return static_cast&amp;lt;T&amp;amp;&amp;gt;(VectorBase::front()); }
};

int main()
{
    Vector&amp;lt;int&amp;gt; v1;
    Vector&amp;lt;short&amp;gt; v2;
    Vector&amp;lt;double&amp;gt; v3;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>template optimization</category>
      <category>thin template</category>
      <category>가벼운 템플릿 기법</category>
      <category>템플릿 최적화</category>
      <category>템플릿 코드 메모리 최적화</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/150</guid>
      <comments>https://devoops.tistory.com/150#entry150comment</comments>
      <pubDate>Thu, 7 Jan 2021 22:45:10 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template) tuple 전체 요소 출력</title>
      <link>https://devoops.tistory.com/149</link>
      <description>&lt;p&gt;&lt;b&gt;가변인자 템플릿(Variadic template)를 활용하여 tuple 전체 요소를 출력&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1610024264923&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;tuple&amp;gt;
using namespace std;

//튜플과 index_sequence를 받아서 튜플 전체 요소를 출력
template&amp;lt;typename TP, size_t ... I&amp;gt; 
void print_tuple_imp(const TP&amp;amp; tp, const index_sequence&amp;lt;I...&amp;gt;&amp;amp;)
{
    int x[] = { get&amp;lt;I&amp;gt;(tp)... };

    for (auto&amp;amp; n : x)
        cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &quot;, &quot;;
}

template&amp;lt;typename TP&amp;gt;
void print_tuple(const TP&amp;amp; tp)
{
    // 튜플 사이즈를 구해서 index_sequence를 생성하여 print_tuple_imp에 전달
    print_tuple_imp(tp, make_index_sequence&amp;lt;tuple_size&amp;lt;TP&amp;gt;::value&amp;gt;());
}

int main()
{
    tuple&amp;lt;int, int, int&amp;gt; tp(1, 2, 3);

    print_tuple(tp);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>index_sequence</category>
      <category>make_index_sequence</category>
      <category>print_tuple</category>
      <category>tuple</category>
      <category>variadic template</category>
      <category>가변인자 템플릿</category>
      <category>템플릿</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/149</guid>
      <comments>https://devoops.tistory.com/149#entry149comment</comments>
      <pubDate>Thu, 7 Jan 2021 21:58:39 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template) tuple을 위한 get 구현</title>
      <link>https://devoops.tistory.com/148</link>
      <description>&lt;p&gt;&lt;b&gt;기반 클래스의 멤버에 접근하는 방법(기반 지식)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기반 클래스의 멤버와 파생클래스의 멤버의 이름이 동일할때는 자신(파생 클래스)의 멤버가 우선&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기반 클래스의 멤버에 접근하는 방법&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;d.Base::value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;static_cast&amp;lt;Base&amp;amp;&amp;gt;(d).value;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;값 캐스팅과 참조 캐스팅&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;static_cast&amp;lt;Base&amp;gt;(d): 임시객체 생성. lvalue가 될 수 없음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;static_cast&amp;lt;Base&amp;amp;&amp;gt;(d): 임시객체를 생성 안함. lvalue가 될 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609943430786&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

struct Base
{
    int value = 10;
};

struct Derived : public Base
{
    int value = 20;
};

int main()
{
    Derived d;

    cout &amp;lt;&amp;lt; d.value &amp;lt;&amp;lt; endl; // 20
    cout &amp;lt;&amp;lt; d.Base::value &amp;lt;&amp;lt; endl; // 10

    cout &amp;lt;&amp;lt; static_cast&amp;lt;Base&amp;gt;(d).value &amp;lt;&amp;lt; endl; // 10 임시객체 생성
    cout &amp;lt;&amp;lt; static_cast&amp;lt;Base&amp;amp;&amp;gt;(d).value &amp;lt;&amp;lt; endl; // 10 참조

    //static_cast&amp;lt;Base&amp;gt;(d).value = 30; // Error
    static_cast&amp;lt;Base&amp;amp;&amp;gt;(d).value = 30; // OK

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Tuple_element&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;tuple이 가진 N번째 요소의 타입을 구하는 템플릿&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿(Main template) 생성, 구현은 불필요함으로 생략&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;0번째 요소를 구하는 부분 특수화 구현&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;N번째 요소를 구하는 부분 특수화 구현(Recursive)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609945835476&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// tuple 메인 템플릿
template&amp;lt;typename ... Types&amp;gt; struct xtuple
{
    static constexpr int N = 0;
};

// tuple 부분 특수화
template&amp;lt;typename T, typename ... Types&amp;gt; 
struct xtuple&amp;lt;T, Types...&amp;gt; : public xtuple&amp;lt;Types...&amp;gt; // 타입을 상속을 통해 재귀 저장 효과
{
    T value;
    xtuple() = default; // 기본 생성자
    xtuple(const T&amp;amp; v, const Types&amp;amp; ... args) 
        : value(v), xtuple&amp;lt;Types...&amp;gt;(args...) {} // Pack expansion으로 가변인자 전달

    static constexpr int N = xtuple&amp;lt;Types...&amp;gt;::N + 1;
};

// 메인 템플릿
template&amp;lt;size_t N, typename TP&amp;gt; struct xtuple_element;

// 요소의 타입을 구할 수 있도록 부분 특수화
template&amp;lt;typename T, typename... Types&amp;gt; struct xtuple_element&amp;lt;0, xtuple&amp;lt;T, Types...&amp;gt;&amp;gt;
{
    typedef T type;
    typedef xtuple&amp;lt;T, Types...&amp;gt; tupleType;
};

// 요소의 타입을 구할 수 있도록 부분 특수화
template&amp;lt;size_t N, typename T, typename... Types&amp;gt; 
struct xtuple_element&amp;lt;N, xtuple&amp;lt;T, Types...&amp;gt;&amp;gt;
{
    typedef typename xtuple_element&amp;lt;N-1, xtuple&amp;lt;Types...&amp;gt;&amp;gt;::type type;
    typedef typename xtuple_element&amp;lt;N-1, xtuple&amp;lt;Types...&amp;gt;&amp;gt;::tupleType tupleType;
};

// xtuple 요소를 꺼내는 함수
template&amp;lt;size_t N, typename TP&amp;gt;
typename xtuple_element&amp;lt;N, TP&amp;gt;::type&amp;amp; xget(TP&amp;amp; tp)
{
    return static_cast&amp;lt;typename xtuple_element&amp;lt;N, TP&amp;gt;::tupleType&amp;amp;&amp;gt;(tp).value;
}

int main()
{
    xtuple&amp;lt;int, double, char&amp;gt; t3(1, 3.4, 'A'); // 1
    
    cout &amp;lt;&amp;lt; xget&amp;lt;1&amp;gt;(t3) &amp;lt;&amp;lt; endl; // 3.4
    xget&amp;lt;1&amp;gt;(t3) = 1.1;
    cout &amp;lt;&amp;lt; xget&amp;lt;1&amp;gt;(t3) &amp;lt;&amp;lt; endl; // 1.1
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>Get</category>
      <category>static_cast</category>
      <category>template</category>
      <category>tuple</category>
      <category>variadic template</category>
      <category>가변인자 템플릿</category>
      <category>참조 캐스팅</category>
      <category>캐스팅</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/148</guid>
      <comments>https://devoops.tistory.com/148#entry148comment</comments>
      <pubDate>Thu, 7 Jan 2021 00:11:53 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template) tuple 만들기</title>
      <link>https://devoops.tistory.com/147</link>
      <description>&lt;p&gt;&lt;b&gt;tuple C++11 표준&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-size=&quot;size14&quot;&gt;서로 다른 타입의 객체를 N개 보관하는 템플릿&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609940929584&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;tuple&amp;gt;
using namespace std;

int main()
{
    tuple&amp;lt;&amp;gt; t0;
    tuple&amp;lt;int&amp;gt; t1(1);
    tuple&amp;lt;int, double, int, char&amp;gt; t4(1, 3.4, 2, 'A');

    get&amp;lt;2&amp;gt;(t4) = 15; // 참조 리턴으로 값 변경 가능

    cout &amp;lt;&amp;lt; get&amp;lt;2&amp;gt;(t4) &amp;lt;&amp;lt; endl; // 2
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;tuple 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;가변인자 템플릿을 사용해서 메인 템플릿(Main template)을 만듬&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;1개의 요소를 보관할 수 있도록 부분 특수화 구현&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;상속을 사용해서 N개를 보관할 수 있게 구현&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;생성자등 필요한 멤버 추가&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609942210027&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// tuple 메인 템플릿
template&amp;lt;typename ... Types&amp;gt; struct xtuple
{
    static constexpr int N = 0;
};

// tuple 부분 특수화
template&amp;lt;typename T, typename ... Types&amp;gt; 
struct xtuple&amp;lt;T, Types...&amp;gt; : public xtuple&amp;lt;Types...&amp;gt; // 타입을 상속을 통해 재귀 저장 효과
{
    T value;
    xtuple() = default; // 기본 생성자
    xtuple(const T&amp;amp; v, const Types&amp;amp; ... args) 
        : value(v), xtuple&amp;lt;Types...&amp;gt;(args...) {} // Pack expansion으로 가변인자 전달

    static constexpr int N = xtuple&amp;lt;Types...&amp;gt;::N + 1;
};

int main()
{
    xtuple&amp;lt;&amp;gt; t0;
    xtuple&amp;lt;int&amp;gt; t1(3);
    xtuple&amp;lt;int, double, char&amp;gt; t4(1, 3.4, 'A');
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>tuple</category>
      <category>tuple 구현</category>
      <category>가변인자 템플릿</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/147</guid>
      <comments>https://devoops.tistory.com/147#entry147comment</comments>
      <pubDate>Wed, 6 Jan 2021 23:11:03 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template) 함수 인자타입 구하기</title>
      <link>https://devoops.tistory.com/146</link>
      <description>&lt;p&gt;&lt;b&gt;함수의 인자 타입을 구하는 traits 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿(Main template)만들고 typedef T type 제공&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 타입인 T 안에 있는 함수 인자 타입을 얻을 수 있도록 부분 특수화&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;T -&amp;gt; R(A1, A2), T -&amp;gt; R(A1, Types...)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;N번째 인자 타입 구하는 방법&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;0번째 인자의 타입을 구하는 부분 특수화 작성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;N번째 인자의 타입을 구하는 부분 특수화 작성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;N == 0이 될때까지 Recursive 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Recuresive 사용시, 함수의 0번째 인자를 제거하고 N-1 사용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;argument_type&amp;lt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;3&lt;/span&gt;&lt;/b&gt;, R(A1, A2, A3, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;A4&lt;/span&gt;&lt;/b&gt;))::type&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;argument_type&amp;lt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;2&lt;/span&gt;&lt;/b&gt;, R(&lt;s&gt;A1&lt;/s&gt;, A2, A3, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;A4&lt;/span&gt;&lt;/b&gt;))::type&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;argument_type&amp;lt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;1&lt;/span&gt;&lt;/b&gt;, R(&lt;s&gt;A1, A2&lt;/s&gt;, A3, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;A4&lt;/span&gt;&lt;/b&gt;))::type&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;argument_type&amp;lt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;0&lt;/span&gt;&lt;/b&gt;, R(&lt;s&gt;A1, A2, A3&lt;/s&gt;, &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;A4&lt;/span&gt;&lt;/b&gt;))::type&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609940387553&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

double hoo(short a, int b, double c) { return 0; }

// 메인 템플릿
template&amp;lt;size_t N, typename T&amp;gt; struct argument_type
{
    typedef T type;
};

// 0번째 인자의 타입을 구하는 부분 특수화 작성
template&amp;lt;typename T, typename A1, typename ... Types&amp;gt; 
struct argument_type&amp;lt;0, T(A1, Types ...)&amp;gt;
{
    typedef A1 type;
};

// N번째 인자의 타입을 구하는 부분 특수화 작성
template&amp;lt;size_t N, typename R, typename A1, typename ... Types&amp;gt; 
struct argument_type&amp;lt;N, R(A1, Types ...)&amp;gt;
{
    typedef
        typename argument_type&amp;lt;N - 1, R(Types...)&amp;gt;::type type;
};

template&amp;lt;typename T&amp;gt; void foo(const T&amp;amp; t)
{
    // T : double(short, int, double)
    typename argument_type&amp;lt;0, T&amp;gt;::type ret;
    cout &amp;lt;&amp;lt; typeid(ret).name() &amp;lt;&amp;lt; endl;
}

int main()
{
    foo(hoo);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>template</category>
      <category>variadic template</category>
      <category>가변인자 템플릿</category>
      <category>함수 인자타입</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/146</guid>
      <comments>https://devoops.tistory.com/146#entry146comment</comments>
      <pubDate>Wed, 6 Jan 2021 22:40:06 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template) 함수 리턴타입 구하기</title>
      <link>https://devoops.tistory.com/145</link>
      <description>&lt;p&gt;&lt;b&gt;함수 정보를 구하는 traits 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿(Primary template)을 만들고 typedef T type 제공&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 타입의 T안에 있는 리턴 타입을 얻을 수 있도록 부분 특수화 구현&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;부분 특수화를 할땡 가변인자 템플릿을 활용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609937896387&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

double hoo(short a, int b) { return 0; }

// 메인 템플릿
template&amp;lt;typename T&amp;gt;
struct result_type
{
    typedef T type;
};

// 함수 타입에 대한 부분 특수화, 가변인자 활용
template&amp;lt;typename T, typename ... Types&amp;gt;
struct result_type&amp;lt;T(Types ... args)&amp;gt;
{
    typedef T type;
};

template&amp;lt;typename T&amp;gt; void foo(const T&amp;amp; t)
{
    // T : double(short, int) 함수 모양
    typename result_type&amp;lt;T&amp;gt;::type ret;
    cout &amp;lt;&amp;lt; typeid(ret).name() &amp;lt;&amp;lt; endl;
}

int main()
{
    foo(hoo);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;traits 잘못 사용할때 처리 방법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿에서 typedef T type을 제공하지 않는 방법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿에서 static_assert()를 사용해서 명시적 에러 메시지 출력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿의 선언만 구현&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609938354930&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

double hoo(short a, int b) { return 0; }

// 1. typedef T type 미제공
template&amp;lt;typename T&amp;gt;
struct result_type
{
};

// 2. static_assert()를 사용해서 에러 메시지 출력
template&amp;lt;typename T&amp;gt;
struct result_type
{
    static_assert(is_function&amp;lt;T&amp;gt;::value, &quot;Not supported type&quot;);
};

// 3. 선언부만 제공
template&amp;lt;typename T&amp;gt;
struct result_type;


// 함수 타입에 대한 부분 특수화
template&amp;lt;typename T, typename ... Types&amp;gt;
struct result_type&amp;lt;T(Types ... args)&amp;gt;
{
    typedef T type;
};

template&amp;lt;typename T&amp;gt; void foo(const T&amp;amp; t)
{
    // T : double(short, int) 함수 모양
    typename result_type&amp;lt;T&amp;gt;::type ret;
    cout &amp;lt;&amp;lt; typeid(ret).name() &amp;lt;&amp;lt; endl;
}

int main()
{
    foo(hoo);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>static_assert</category>
      <category>template</category>
      <category>traits</category>
      <category>variadic template</category>
      <category>가변인자 템플릿</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/145</guid>
      <comments>https://devoops.tistory.com/145#entry145comment</comments>
      <pubDate>Wed, 6 Jan 2021 22:06:49 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template), fold expression(C++17)</title>
      <link>https://devoops.tistory.com/144</link>
      <description>&lt;p&gt;&lt;b&gt;Parameter Pack 각 요소 꺼내기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pack Expansion -&amp;gt; array or tuple에 담기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609859148518&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;tuple&amp;gt;
using namespace std;

template&amp;lt;typename ... Types&amp;gt; 
void foo(Types ... args)
{
    // 각각의 타입별 값을 tuple 개별 요소로 추가
    tuple&amp;lt;Types...&amp;gt; tp(args...);

    cout &amp;lt;&amp;lt; get&amp;lt;0&amp;gt;(tp) &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; get&amp;lt;1&amp;gt;(tp) &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; get&amp;lt;2&amp;gt;(tp) &amp;lt;&amp;lt; endl;
}


int main()
{
    foo(1, 3.4, &quot;AA&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&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;재귀 호출과 유사한 호출식을 사용하기
&lt;ul&gt;
&lt;li&gt;1번째 인자는 이름 있는 변수 2번째 인자는 가변 인자로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609859363122&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;tuple&amp;gt;
using namespace std;

void foo() {} // 재귀 호출 종료용

template&amp;lt;typename T, typename ... Types&amp;gt;
void foo(T value, Types ... args)
{
    cout &amp;lt;&amp;lt; value &amp;lt;&amp;lt; endl;
    foo(args...); 
    // 아래처럼 반복 호출 됨
    // foo(3.4, &quot;AA&quot;);
    // foo(&quot;AA&quot;);
    // foo();
}


int main()
{
    foo(1, 3.4, &quot;AA&quot;); // value : 1, args : 3.4, &quot;AA&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;fold expression(C++17)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이항 연산자를 사용해서 parameter pack안에 있는 요소에 연산을 수행하는 문법&lt;/li&gt;
&lt;li&gt;parameter pack의 이름에서 ... 붙이지 않고 사용
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;pack expansion : &lt;span style=&quot;color: #ee2323;&quot;&gt;args...&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;fold expression : &lt;span style=&quot;color: #ee2323;&quot;&gt;args + ...&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;4가지 형태(args:1,2,3,4)
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;unary right fold: ( args op ... )
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;(args + ... ) // 1+(2+(3+4))&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;unary left fold : (... op args)
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;(... + args) // ((1+2)+3)+4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;binary right fold : ( args op ... op init)
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;( args + ... + 10) // 1+(2+3(4+10)))&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;binary left fold : ( init op ... op args)
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;(10 + ... + args) // (((10+1)+2)+3)+4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609860554715&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename ... Types&amp;gt;
void foo(Types ... args)
{

    // args 값을 모두 호출할 수 있음
    //binary left fold : ( init op ... op args)
    (cout &amp;lt;&amp;lt; ... &amp;lt;&amp;lt; args);
}

int main()
{
    foo(1, 2, 3);
    (((cout &amp;lt;&amp;lt; 1) &amp;lt;&amp;lt; 2) &amp;lt;&amp;lt; 3);
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1609860864282&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;

vector&amp;lt;int&amp;gt; v;

template&amp;lt;typename ... Types&amp;gt;
void foo(Types ... args)
{
    (v.push_back(args), ...);
    for (auto n : v)
        cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; endl;
}

int main()
{
    foo(1, 2, 3);
    (((cout &amp;lt;&amp;lt; 1) &amp;lt;&amp;lt; 2) &amp;lt;&amp;lt; 3);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>C++ Template</category>
      <category>C++ 템플릿</category>
      <category>fold expression</category>
      <category>pack expansion</category>
      <category>가변인자 템플릿</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/144</guid>
      <comments>https://devoops.tistory.com/144#entry144comment</comments>
      <pubDate>Wed, 6 Jan 2021 00:34:50 +0900</pubDate>
    </item>
    <item>
      <title>C++ 가변인자 템플릿(Variadic template)</title>
      <link>https://devoops.tistory.com/143</link>
      <description>&lt;p&gt;가변인자 템플릿(Variadic template)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;C++11부터 지원되는 문법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;가변인자 템플릿(클래스 템플릿, 함수 템플릿)의 기본 모양&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;가변인자 템플릿의 인자 &quot;Types&quot;는 여러개의 타입을 나타냄&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;가변인자 함수 템플릿의 인자인 &quot;args&quot;안에는 여러개의 값이 들어있고 &quot;&lt;span style=&quot;color: #ee2323;&quot;&gt;Parameter Pack&lt;/span&gt;&quot;이라고 함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609853031302&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 가변인자 클래스 템플릿.
template&amp;lt;typename ... Types&amp;gt; class tuplex
{

};

// 가변인자 함수 템플릿
template&amp;lt;typename ... Types&amp;gt;
void foo(Types ... args)
{

}

int main()
{
    // 가변인자 클래스 템플릿(타입 생략, 복수의 타입까지...)
    tuplex&amp;lt;&amp;gt; t0p;
    tuplex&amp;lt;int&amp;gt; t1;
    tuplex&amp;lt;int, char&amp;gt; t2;
    
    // 가변인자 함수 템플릿(인자 생략, 복수의 인자까지...)
    foo();
    foo(1);
    foo(1, 3.4, &quot;A&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Parameter Pack&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;가변인자 템플릿으로 전달받은 파라미터 집합을 &lt;span style=&quot;color: #ee2323;&quot;&gt;Parameter Pack&lt;/span&gt;이라 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;sizeof...&lt;/span&gt;(&lt;span style=&quot;color: #006dd7;&quot;&gt;args&lt;/span&gt;), &lt;span style=&quot;color: #ee2323;&quot;&gt;sizeof...&lt;/span&gt;(&lt;span style=&quot;color: #006dd7;&quot;&gt;Types&lt;/span&gt;) 함수를 이용해서 Parameter Pack 요소의 갯수를 얻어 올 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;goo(&lt;span style=&quot;color: #006dd7;&quot;&gt;args...&lt;/span&gt;); 받은 Parameter Pack을 다시 전달할때 요소 전체를 풀어쓰는 방법을 &lt;span style=&quot;color: #ee2323;&quot;&gt;Pack Expansion&lt;/span&gt;이라 함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609853922049&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// Pack expansion을 통해 Parameter Pack을 전달 받을 함수
void goo(int n, double d, const char* s)
{
    cout &amp;lt;&amp;lt; &quot;goo : &quot; &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; d &amp;lt;&amp;lt; &quot;, &quot; &amp;lt;&amp;lt; s &amp;lt;&amp;lt; endl;
    // 1, 3.4, &quot;AAA&quot;
}

// 가변인자 함수 템플릿
template&amp;lt;typename ... Types&amp;gt;
void foo(Types ... args)
{
    // args : Parameter Pack
    
    cout &amp;lt;&amp;lt; sizeof...(args) &amp;lt;&amp;lt; endl; // 3
    cout &amp;lt;&amp;lt; sizeof...(Types) &amp;lt;&amp;lt; endl; // 3

    //goo(args); // Error
    goo(args...); // Pack expansion
                  // goo( 1, 3.4, &quot;AAA&quot;)
}

int main()
{
    //foo();
    //foo(1);
    foo(1, 3.4, &quot;AAA&quot;); 
        // Types : int, double, const char*
        // args : 1, 3.4, &quot;AAA&quot;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Pack Expansion&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Parameter Pack을 사용하는 패턴에 &quot;...&quot; 붙이면 해당 패턴이 ',' 구분자로 확장되는 형태임&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;args이 1, 2, 3을 가지고 있을때&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;args... -&amp;gt; 1, 2, 3&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;(--args)... -&amp;gt; 0, 1, 2&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;func(args)... -&amp;gt; func(1), func(2), func(3)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;func(args...) -&amp;gt; func(1, 2, 3)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;func2(func(args...)) -&amp;gt; func2(func(1, 2, 3))&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;func2(func(args)...)) -&amp;gt; func2(func(1), func(2), func(3))&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Pack Expansion은 &lt;span style=&quot;color: #ee2323;&quot;&gt;함수 호출 인자&lt;/span&gt; 또는 &lt;span style=&quot;color: #ee2323;&quot;&gt;list 초기화를 사용한 표현식&lt;/span&gt;에서만 사용할 수 있음&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;배열 이용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;컴파일러에 따라 빈값이 허용 안될 수 있으므로 첫번째 요소를 더미로 0으로 지정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수가 반환 타입이 void 경우 대비해서 대체 반환값 (x, 0) 패턴 사용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;int x[] = { 0, (print(args), 0)... };&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;초기화 리스트 이용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;빈값이 허용 됨으로 배열에 비해서 첫번째 요소 더미 0을 생략 할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;initializer_list&amp;lt;int&amp;gt; e = { (print(args), 0)... };&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609856444906&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

void goo(int n, double d, const char* s)
{
    cout &amp;lt;&amp;lt; &quot;goo : &quot; &amp;lt;&amp;lt; n &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; d &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; s &amp;lt;&amp;lt; endl;
}

int hoo(int a) { return -a; }

int print(int a)
{
    cout &amp;lt;&amp;lt; a &amp;lt;&amp;lt; &quot;, &quot;;
    return 0;
}

template&amp;lt;typename ... Types&amp;gt;
void foo(Types ... args)
{
    int x[] = { args... }; // Pack expansion
    for (auto n : x)
        cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; endl;

    //print(args); // Error(함수 호출 인자 or list 초기화가 아님)
    //print(args...); // Error(함수 호출 인자 or list 초기화가 아님)
    //print(args)...; // Error(함수 호출 인자 or list 초기화가 아님)

    // 배열 이용
    int ea[] = { 0, (print(args), 0)... };

    // 초기화 리스트 이용
    initializer_list&amp;lt;int&amp;gt; ei = { (print(args), 0)... };

}

int main()
{
    foo(1, 2, 3);
     // Types : int, int, int
     // args : 1, 2, 3
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Expansion 예제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1609856979232&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename ... Types&amp;gt; void foo(Types ... args)
{
    // Types : int, double

    int x[] = { args... };
    pair&amp;lt;Types...&amp;gt; p1; // pair&amp;lt;int, double&amp;gt; // OK
    tuple&amp;lt;Types...&amp;gt; t1; // tuple&amp;lt;int, double&amp;gt; // OK

    tuple&amp;lt;pair&amp;lt;Types...&amp;gt;&amp;gt; t2; // tuple&amp;lt;pair&amp;lt;int, double&amp;gt;&amp;gt; // OK
    tuple&amp;lt;pair&amp;lt;Types&amp;gt;...&amp;gt; t3; // tuple&amp;lt;pair&amp;lt;int&amp;gt;, pair&amp;lt;double&amp;gt;&amp;gt; // Error

    tuple&amp;lt;pair&amp;lt;int, Types&amp;gt;...&amp;gt; t4; // tuple&amp;lt;pair&amp;lt;int, int&amp;gt;, pair&amp;lt;int, double&amp;gt;&amp;gt; // OK

    pair&amp;lt;tuple&amp;lt;Types...&amp;gt;&amp;gt; p2; // pair&amp;lt;tuple&amp;lt;int, double&amp;gt;&amp;gt; // Error
    pair&amp;lt;tuple&amp;lt;Types&amp;gt;...&amp;gt; p3; // pair&amp;lt;tuple&amp;lt;int&amp;gt;, tuple&amp;lt;double&amp;gt;&amp;gt; // OK

}

int main()
{
    foo(1, 3.4); 
      // args : 1, 3.4
      // Types : int, double
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>C++ 템플릿</category>
      <category>variadic template</category>
      <category>가변인자 클래스 템플릿</category>
      <category>가변인자 템플릿</category>
      <category>가변인자 함수 템플릿</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/143</guid>
      <comments>https://devoops.tistory.com/143#entry143comment</comments>
      <pubDate>Tue, 5 Jan 2021 23:30:13 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 type_traits(C++11 표준 remove_pointer, is_pointer)</title>
      <link>https://devoops.tistory.com/142</link>
      <description>&lt;p&gt;&lt;b&gt;C++11 표준 type traits&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;변형된 타입을 얻는 traits&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;typename remove_pointer&amp;lt;T&amp;gt;::type;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;remove_pointer_t&amp;lt;T&amp;gt; n; // C++14&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;타입의 정보를 조사하는 traits&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;bool b = is_pointer&amp;lt;T&amp;gt;::value;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;bool b = is_pointer_v&amp;lt;T&amp;gt;;&amp;nbsp; // C++17&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 오버로딩 사용(true_type, false_type) 활용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;간소화된 버전&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;C++14 기본 제공&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;remove_pointer_t&amp;lt;T&amp;gt; n;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;C++17 기본 제공&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;bool b = is_pointer_v&amp;lt;T&amp;gt;;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609768169389&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

//using을 사용해서 간소화 가능
template&amp;lt;typename T&amp;gt;
using remove_pointer_type = typename remove_pointer&amp;lt;T&amp;gt;::type;

// C++17에서는 variable template을 사용해서 간소화 가능
//template&amp;lt;typename T&amp;gt;
//inline constexpr bool is_pointer_v = is_pointer&amp;lt;T&amp;gt;::value;

template&amp;lt;typename T&amp;gt; void foo(T a)
{
    // 포인터를 제거한 타입 반환
    typename remove_pointer&amp;lt;T&amp;gt;::type rawType;
    remove_pointer_type&amp;lt;T&amp;gt; rawType2;

    // 포인터 타입 여부 확인
    bool isPointer = is_pointer&amp;lt;T&amp;gt;::value;
}
int main()
{
    int n = 0;
    foo(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;C++11 표준 type_traits 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;is_array&amp;lt;T&amp;gt;::value : 배열 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;extent&amp;lt;T, 0&amp;gt;::value : 배열 각 차원의 요소 수&amp;nbsp;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;is_same&amp;lt;T, U&amp;gt;::value : 타입 같음 비교&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;remove_cv&amp;lt;T, U&amp;gt;::type : const, volatile 속성 제거(타입 비교시 이용)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;decay&amp;lt;T, U&amp;gt;::type : 배열을 포인터화 사용 필요 시&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609770098522&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

// 배열 정보 조사하기
// array =&amp;gt; pointer : decay
template&amp;lt;typename T&amp;gt; void foo(T&amp;amp; a)
{
    if (is_array&amp;lt;T&amp;gt;::value)
    {
        cout &amp;lt;&amp;lt; &quot;array&quot; &amp;lt;&amp;lt; endl;

        cout &amp;lt;&amp;lt; extent&amp;lt;T, 0&amp;gt;::value &amp;lt;&amp;lt; endl;
        cout &amp;lt;&amp;lt; extent&amp;lt;T, 1&amp;gt;::value &amp;lt;&amp;lt; endl;
    }
}

template&amp;lt;typename T, typename U&amp;gt; void hoo(T a, U b)
{
    // 두 타입 비교
    bool ret1 = is_same&amp;lt;T, U&amp;gt;::value;

    // 배열일 경우 포인터화 비교
    bool ret2 = is_same&amp;lt;typename decay&amp;lt;T&amp;gt;::type, typename decay&amp;lt;U&amp;gt;::type&amp;gt;::value;

    // const, volatile 제거 후 비교
    bool ret3 = is_same&amp;lt;typename remove_cv&amp;lt;T&amp;gt;::type, typename remove_cv&amp;lt;U&amp;gt;::type&amp;gt;::value;

    cout &amp;lt;&amp;lt; ret1 &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; ret2 &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; ret3 &amp;lt;&amp;lt; endl;
}

int main()
{
    int x = 1;
    const int cx = 1;
    int* xp = &amp;amp;x;
    int a[3][2] = { 1,2,3,4,5,6 };
    foo(a);
    hoo(x, cx);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>C++ traits</category>
      <category>C++11</category>
      <category>extent</category>
      <category>is_array</category>
      <category>is_decay</category>
      <category>is_pointer</category>
      <category>is_same</category>
      <category>remove_cv</category>
      <category>remove_pointer</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/142</guid>
      <comments>https://devoops.tistory.com/142#entry142comment</comments>
      <pubDate>Mon, 4 Jan 2021 22:53:01 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 traits(함수 반환 값/파라미터)</title>
      <link>https://devoops.tistory.com/141</link>
      <description>&lt;p&gt;&lt;b&gt;함수의 리턴타입, 인자타입 정보를 구하는 traits 만들기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿(Main template)을 만들고 typedef T type 제공(C++11 using 동일)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;부분 특수화(Partial specialization)를 통한 원하는 타입을 얻을 수 있도록 T 타입 분할&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수 타입 T(double(short, int))를 리턴타입 double과 인자타입(short, int)로 분리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;T(double(short, int)) -&amp;gt; R(A1, A2)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿의 활용도가 없을 경우 내부 type은 제거 해도 됨&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609766505763&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

double hoo(short a, int b) { return 0; }

// 반환 타입에 대한 메인 템플릿
template&amp;lt;typename T&amp;gt; 
struct result_type
{
    typedef T type;
};

// 함수타입에 대한 부분 특수화
template&amp;lt;typename T, typename A1, typename A2&amp;gt; 
struct result_type&amp;lt;T(A1, A2)&amp;gt;
{
    typedef T type;
};

// 인자는 복수개이므로 N 파라미터 추가로 필요
template&amp;lt;typename T, size_t N&amp;gt;
struct argument_type
{
    typedef T type;
};

// 첫번째 인자에 대한 부분 특수화
template&amp;lt;typename R, typename A1, typename A2&amp;gt;
struct argument_type&amp;lt;R(A1, A2), 0&amp;gt;
{
    typedef A1 type;
};

// 두번째 인자에 대한 부분 특수화
template&amp;lt;typename R, typename A1, typename A2&amp;gt;
struct argument_type&amp;lt;R(A1, A2), 1&amp;gt;
{
    typedef A2 type;
};

template&amp;lt;typename T&amp;gt; void foo(T&amp;amp; t)
{
    // T : double(short, int)
    typename result_type&amp;lt;T&amp;gt;::type ret_type;
    typename argument_type&amp;lt;T, 0&amp;gt;::type arg_type0;
    typename argument_type&amp;lt;T, 1&amp;gt;::type arg_type1;

    cout &amp;lt;&amp;lt; typeid(ret_type).name() &amp;lt;&amp;lt; endl; // double
    cout &amp;lt;&amp;lt; typeid(arg_type0).name() &amp;lt;&amp;lt; endl; // short
    cout &amp;lt;&amp;lt; typeid(arg_type1).name() &amp;lt;&amp;lt; endl; // int
}
int main()
{
    foo(hoo);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;C++11 표준의 함수 리턴 타입 구하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;result_of(C++17 미만)&lt;/li&gt;
&lt;li&gt;invoke_result(C++17 이상)&lt;/li&gt;
&lt;li&gt;decltype 사용해서 구현(일반함수, 함수 객체, 람다표현식등의 모든 callable object 고려)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>C++ Template</category>
      <category>function argument</category>
      <category>function result</category>
      <category>template</category>
      <category>traits</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/141</guid>
      <comments>https://devoops.tistory.com/141#entry141comment</comments>
      <pubDate>Mon, 4 Jan 2021 22:28:25 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 type modification(remove_pointer)</title>
      <link>https://devoops.tistory.com/140</link>
      <description>&lt;p&gt;&lt;b&gt;type traits 기능(C++11)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;type에 대한 query : is_pointer&amp;lt;&amp;gt;, is_array&amp;lt;&amp;gt;, extent&amp;lt;&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;type에 대한 변형 타입 : remove_pointer&amp;lt;&amp;gt;, add_pointer&amp;lt;&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609763282352&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; void foo(T a)
{
    bool b = is_pointer&amp;lt;T&amp;gt;::value;
    typename remove_pointer&amp;lt;T&amp;gt;::type t;
    
    cout &amp;lt;&amp;lt; typeid(t).name() &amp;lt;&amp;lt; endl;
}

int main()
{
    int n = 10;
    foo(n);
    foo(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;remove_pointer 구현 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;remove_pointer_custom 메인 템플릿 생성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;int -&amp;gt; int 반환&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;remove_pointer_custom 부분 특수화(Partial specialization) 생성&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;int* -&amp;gt; int 반환&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609763529367&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// Main template
template&amp;lt;typename T&amp;gt; 
struct remove_pointer_custom
{
    typedef T type;
};

// Partial specialization
template&amp;lt;typename T&amp;gt; 
struct remove_pointer_custom&amp;lt;T*&amp;gt;
{
    typedef T type;
};

template&amp;lt;typename T&amp;gt; void foo(T a)
{
    // 값이 아닌 타입을 꺼낼때는 typename을 꼭 사용 필요
    typename remove_pointer_custom&amp;lt;T&amp;gt;::type t;

    cout &amp;lt;&amp;lt; typeid(t).name() &amp;lt;&amp;lt; endl;
}

int main()
{
    int n = 10;
    foo(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;remove_all_pointer 구현 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중첩 포인터까지 모두 제거 되는 remove_pointer 구하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609765140408&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; 
struct remove_all_pointer_custom
{
    typedef T type;
};

template&amp;lt;typename T&amp;gt; 
struct remove_all_pointer_custom&amp;lt;T*&amp;gt;
{
    // 포인터 타입일때까지 포인터를 제거하며 자기 자신을 호출하고 최종 메인 템플릿이 호출됨
    typedef typename remove_all_pointer_custom&amp;lt;T&amp;gt;::type type;
};

int main()
{
    typename remove_all_pointer_custom&amp;lt;int**&amp;gt;::type n;
    cout &amp;lt;&amp;lt; typeid(n).name() &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>C++ Template</category>
      <category>remove_all_pointer</category>
      <category>remove_pointer</category>
      <category>type modification</category>
      <category>type traits</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/140</guid>
      <comments>https://devoops.tistory.com/140#entry140comment</comments>
      <pubDate>Mon, 4 Jan 2021 22:15:45 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 integral_constant</title>
      <link>https://devoops.tistory.com/139</link>
      <description>&lt;p&gt;&lt;b&gt;integral_constant&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 타임에 결정된 상수 값을 별도 타입화 하여 함수 오버로딩을 할 수 있도록 만드는 int2type 기술&lt;/li&gt;
&lt;li&gt;int2type 기술을 C++11에서 표준화한 integral_constant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;기본 함수 오버로딩(Function overloading)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이자의 개수가 다르거나 인자 타입이 다르면 아래와 같이 인수에 따라 서로 다른 함수가 호출 되게 할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;인자가 개수가 같고 인자의 타입도 같을때 다른 함수가 되게 하려면?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609680566432&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

void foo(int n) {}
void foo(double d) {}

int main()
{
    foo(1); // foo(int)
    foo(1.2); // foo(double)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;int2type&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;컴파일 타임 정수형 상수를 각각의 독립된 타입으로 만드는 기술&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;int2type을 사용하면 컴파일 타임에 결정된 정수형 상수를 모두 다른 타입으로 만들 수 있음&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1, 2는 같은 타입이지만, int2type&amp;lt;1&amp;gt;, int2type&amp;lt;2&amp;gt;는 다른 타입&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;int2type을 함수 오버로딩에 사용하거나 템플릿 인자, 상속등에 사용할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609681168500&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 같은 정수형 타입이지만 값에 따라 별도의 타입으로 생성
template&amp;lt;int N&amp;gt; struct int2type
{
    static constexpr int value = N;
};

int main()
{
    int2type&amp;lt;1&amp;gt; t0; // int2type&amp;lt;1&amp;gt; 타입
    int2type&amp;lt;2&amp;gt; t1; // int2type&amp;lt;2&amp;gt; 타입
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;int2type 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;printv 함수에서 받은 값의 포인터 타입 여부에 따라 분기처리 코드가 작성되어 값과 포인터 참조값을 출력하도록 되어 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;포인터 여부는 컴파일 타임에 체크되지만 if 구문이 런타임 조건문으로 하위 코드들은 모두 컴파일 대상&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;포인터가 아닌 값에 대해서는 사용할 수 없는 구분이 포함되어 간접 참조 에러가 발생함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;간접 참조 에러가 발생하는 구문을 별도의 함수 템플릿으로 분리함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;각 함수 템플릿은 int2type을 활용하여 인자 타입으로 구분하여 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;동일 이름을 가지는 함수가 여러개 있을때, 어느 함수를 호출할지는 컴파일 타임에 결정됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;호출이 결정되지 않은 템플릿은 instantiation 되지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609682014299&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

// 포인터 타입 체크용 메인 템플릿
template&amp;lt;typename T&amp;gt; struct is_pointer_custom
{
    //enum { value = false }; 
    static constexpr bool value = false; // c++11
};

// 포인터 타입에 대해서 부분 특수화 필요
template&amp;lt;typename T&amp;gt; struct is_pointer_custom&amp;lt;T*&amp;gt;
{
    //enum { value = true };
    static constexpr bool value = true; // c++
};
...

// 같은 정수형 타입이지만 값에 따라 별도의 타입으로 생성되는 타입 도구
template&amp;lt;int N&amp;gt; struct int2type
{
    static constexpr int value = N;
};

// 컴파일 타임 상수 값 구분용 함수 템플릿
template&amp;lt;typename T&amp;gt;
void printv_imp(T v, int2type&amp;lt;1&amp;gt;)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot; : &quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
}

// 컴파일 타임 상수 값 구분용 함수 템플릿
template&amp;lt;typename T&amp;gt;
void printv_imp(T v, int2type&amp;lt;0&amp;gt;)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; endl;
}

// 값을 받아서 출력하고, 포인터일 경우 포인터의 값까지 출력
template&amp;lt;typename T&amp;gt; void printv(T v)
{
    // 아래의 조건으로 분기 코드 작성시 if 구문이 런타임 조건문으로
    // 포인터가 아닌 값에 대해서 컴파일 에러 발생
    //if(is_pointer_custom&amp;lt;T&amp;gt;::value)
    //    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot; : &quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
    //else
    //    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; endl;

    // 출력 구현부를 별도로 분리하여 함수 템플릿으로 타입을 구분하여 문제 해결 가능
    printv_imp(v, int2type&amp;lt;is_pointer_custom&amp;lt;T&amp;gt;::value&amp;gt;());
    // is_pointer_custom 반환 값에 의해(포인터: int2type&amp;lt;1&amp;gt;, 포인터 아님: int2type&amp;lt;0&amp;gt; 타입)
}

int main()
{
    int n = 3;
    printv(n);
    printv(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;integral_constant 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;int뿐 아니라 모든 정수 계열 상수 값을 타입으로 만들 수 있게 하는 템플릿(실수는 템플릿 인자 사용X)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;bool, char, short, int, long, long long&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;true_type, false_type&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;true/false: 참 거짓을 나타내는 값, 서로 같은 타입&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;true_type/false_type: 참 거짓을 나타내는 값, 서로 다른 타입&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;is_pointer등의 type_traits를 만들때 intergral_constant를 기반 클래스로 사용하여 간소화 및 가독성을 높일 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;T가 포인터가 아니라면, value = false, 기반 클래스는 false_type&lt;/li&gt;
&lt;li&gt;T가 포인터라면, value = true, 기반 클래스는 true_type&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609683092112&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
using namespace std;

template&amp;lt;typename T, T N&amp;gt; 
struct integral_constant
{
    static constexpr T value = N;
};

// int 타입 0, 1 서로 다른 타입
integral_constant&amp;lt;int, 0&amp;gt; t0;
integral_constant&amp;lt;int, 1&amp;gt; t1;

// short 타입, 0, 1 서로 다른 타입
integral_constant&amp;lt;short, 0&amp;gt; s0;
integral_constant&amp;lt;short, 1&amp;gt; s1;

// bool 타입, true, false 서로 다른 타입
integral_constant&amp;lt;bool, true&amp;gt; tb1;
integral_constant&amp;lt;bool, false&amp;gt; tb0;

// bool 타입은 활용 빈도가 높으므로 true_type, false_type 별칭 만들어서 사용
typedef integral_constant&amp;lt;bool, true&amp;gt; true_type;
typedef integral_constant&amp;lt;bool, false&amp;gt; false_type;

template&amp;lt;typename T&amp;gt;
struct is_pointer : false_type
{
    // false_type 상속으로 아래 코드 생략
    //static constexpr bool value = false;
};

template&amp;lt;typename T&amp;gt;
struct is_pointer&amp;lt;T*&amp;gt; : true_type
{
    // true_type 상속으로 아래 코드 생략
    //static constexpr bool value = true;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;C++11 type_traits 활용하여 int2type 예제 간소화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;C++11 &amp;lt;type_traits&amp;gt;헤더 포함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;int2type&amp;lt;0&amp;gt;, int2type&amp;lt;1&amp;gt; -&amp;gt; integral_constant&amp;lt;0&amp;gt;, integral_constant&amp;lt;1&amp;gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;integral_constant&amp;lt;0&amp;gt;, integral_constant&amp;lt;1&amp;gt; -&amp;gt; false_type, true_type&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609683864607&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

// 컴파일 타임 상수 값 구분용 함수 템플릿
template&amp;lt;typename T&amp;gt;
void printv_imp(T v, true_type)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot; : &quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
}

// 컴파일 타임 상수 값 구분용 함수 템플릿
template&amp;lt;typename T&amp;gt;
void printv_imp(T v, false_type)
{
    cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; endl;
}

// 값을 받아서 출력하고, 포인터일 경우 포인터의 값까지 출력
template&amp;lt;typename T&amp;gt; void printv(T v)
{
    printv_imp(v, is_pointer&amp;lt;T&amp;gt;());
}

int main()
{
    int n = 3;
    printv(n);
    printv(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;C++17 if constexpr를 사용하여 컴파일 타임에 분기처리 가능&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1609684371892&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

// 값을 받아서 출력하고, 포인터일 경우 포인터의 값까지 출력
template&amp;lt;typename T&amp;gt; void printv(T v)
{
    if constexpr(is_pointer&amp;lt;T&amp;gt;::value)
        cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; &quot; : &quot; &amp;lt;&amp;lt; *v &amp;lt;&amp;lt; endl;
    else
        cout &amp;lt;&amp;lt; v &amp;lt;&amp;lt; endl;
}

int main()
{
    int n = 3;
    printv(n);
    printv(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>false_type</category>
      <category>int2type</category>
      <category>integral_constant</category>
      <category>traits</category>
      <category>true_type</category>
      <category>type query</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/139</guid>
      <comments>https://devoops.tistory.com/139#entry139comment</comments>
      <pubDate>Sun, 3 Jan 2021 23:36:35 +0900</pubDate>
    </item>
    <item>
      <title>c++ 템플릿 type_traits 배열 타입 체크(is_array)</title>
      <link>https://devoops.tistory.com/138</link>
      <description>&lt;p&gt;&lt;b&gt;is_array 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;간단히 템플릿 파라미터 T가 배열 타입 여부 확인 도구&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿(Main template)에서 false 반환( value = false )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;배열 타입 부분 특수화(Partial specialization)에서 true 반환( value = true )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;타입을 정확히 알아야 함&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;int&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;[3]&lt;/span&gt;; 에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;x&lt;/span&gt;는 변수 이름, 변수 이름을 제외한 나머지 요소(&lt;span style=&quot;color: #ee2323;&quot;&gt;int[3]&lt;/span&gt;)이 타입임&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;unknown size array type(T[])에 대해서도 부분 특수화가 필요함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609666693720&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; struct is_array_custom
{
    static constexpr bool value = false;
};

// 크기를 알 수 있는 배열의 부분 특수화
template&amp;lt;typename T, size_t N&amp;gt;
struct is_array_custom&amp;lt;T[N]&amp;gt;
{
    static constexpr bool value = true;
};

// 크기를 알 수 없는 배열의 부분 특수화
template&amp;lt;typename T, size_t N&amp;gt;
struct is_array_custom&amp;lt;T[N]&amp;gt;
{
    static constexpr bool value = true;
};

template&amp;lt;typename T&amp;gt; void foo(T&amp;amp; a)
{
    // 크기를 알 수 있는 배열 확인
    if (is_array_custom&amp;lt;T&amp;gt;::value)
        cout &amp;lt;&amp;lt; &quot;array&quot; &amp;lt;&amp;lt; endl;
    else
        cout &amp;lt;&amp;lt; &quot;not array&quot; &amp;lt;&amp;lt; endl;
      
    // 크기를 알 수 없는 배열을 사용하는 패턴도 존재함
    //if (is_array_custom&amp;lt;int[]&amp;gt;::value)
}

int main()
{
    int x[3] = { 1, 2, 3 };
    foo(x);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;is_array 배열 크기 구하기&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;부분 특수화로 배열의 크기도 구할 수 있음&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;c++11 extent&amp;lt;T, 0&amp;gt;::value 존재&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609667066101&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; struct is_array_custom
{
    static constexpr bool value = false;
    static constexpr size_t size = -1;
};

//사이즈를 알 수 있는 배열에 대한 부분 특수화에서 N이 배열의 크기
template&amp;lt;typename T, size_t N&amp;gt;
struct is_array_custom&amp;lt;T[N]&amp;gt;
{
    static constexpr bool value = true;
    static constexpr size_t size = N;
};

template&amp;lt;typename T&amp;gt; void foo(T&amp;amp; a)
{
    if (is_array_custom&amp;lt;T&amp;gt;::value)
        cout &amp;lt;&amp;lt; &quot;size of array : &quot; &amp;lt;&amp;lt; is_array_custom&amp;lt;T&amp;gt;::size &amp;lt;&amp;lt; endl;
}

int main()
{
    int x[3] = { 1, 2, 3 };
    foo(x);
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>array_size</category>
      <category>C++</category>
      <category>is_array</category>
      <category>template</category>
      <category>type_traits</category>
      <category>배열</category>
      <category>배열 사이즈</category>
      <category>템플릿 부분 특수화</category>
      <category>템플릿 특수화</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/138</guid>
      <comments>https://devoops.tistory.com/138#entry138comment</comments>
      <pubDate>Sun, 3 Jan 2021 18:48:10 +0900</pubDate>
    </item>
    <item>
      <title>c++ 템플릿 type_traits 포인터 타입 체크(is_pointer)</title>
      <link>https://devoops.tistory.com/137</link>
      <description>&lt;p&gt;&lt;b&gt;type traits 개념&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;컴파일 타임에 타입에 대한 정보를 얻거나 변형된 타입을 얻을때 사용하는 도구(메타 함수)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;lt;type_traits&amp;gt; 헤더로 제공됨(c++11)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;type query를 위한 type traits 만드는 방법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 템플릿(Primary template)에서 false 반환( value = false )&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;부분 특수화(Partial specialization)에서 true 반환( value = true )&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;is_pointer 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;간단히 템플릿 파라미터 T가 포인터 타입 여부 확인 도구&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;메인 템플릿(Primary template)에서 false 반환( value = false )&lt;/li&gt;
&lt;li&gt;포인터 타입용 부분 특수화(Partial specialization)에서 true 반환( value = true )&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609643721953&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; struct is_pointer_custom
{
    enum { value = false }; 
};

// 포인터 타입에 대해서 부분 특수화 필요
template&amp;lt;typename T&amp;gt; struct is_pointer_custom&amp;lt;T*&amp;gt;
{
    enum { value = true };
};

template&amp;lt;typename T&amp;gt; void foo(T v)
{
    if (is_pointer_custom&amp;lt;T&amp;gt;::value)
        cout &amp;lt;&amp;lt; &quot;pointer&quot; &amp;lt;&amp;lt; endl;
    else
        cout &amp;lt;&amp;lt; &quot;not pointer&quot; &amp;lt;&amp;lt; endl;
}

int main()
{
    int n = 3;
    foo(n);
    foo(&amp;amp;n);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;is_pointer 개선 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;c++11 기준 코드 개선&lt;/li&gt;
&lt;li&gt;좀더 다양한 포인터 타입 지원(const, volatile, const volatile)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609645608306&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;typename T&amp;gt; struct is_pointer_custom
{
    //enum { value = false }; 
    static constexpr bool value = false; // c++11
};

// 포인터 타입에 대해서 부분 특수화 필요
template&amp;lt;typename T&amp;gt; struct is_pointer_custom&amp;lt;T*&amp;gt;
{
    //enum { value = true };
    static constexpr bool value = true; // c++
};

// 포인터 타입에 대해서 부분 특수화 필요
template&amp;lt;typename T&amp;gt; struct is_pointer_custom&amp;lt;T* const&amp;gt;
{
    //enum { value = true };
    static constexpr bool value = true; // c++
};

// 포인터 타입에 대해서 부분 특수화 필요
template&amp;lt;typename T&amp;gt; struct is_pointer_custom&amp;lt;T* volatile&amp;gt;
{
    //enum { value = true };
    static constexpr bool value = true; // c++
};

// 포인터 타입에 대해서 부분 특수화 필요
template&amp;lt;typename T&amp;gt; struct is_pointer_custom&amp;lt;T* const volatile&amp;gt;
{
    //enum { value = true };
    static constexpr bool value = true; // c++
};

int main()
{
    cout &amp;lt;&amp;lt; is_pointer_custom&amp;lt;int&amp;gt;::value &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; is_pointer_custom&amp;lt;int*&amp;gt;::value &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; is_pointer_custom&amp;lt;int* const&amp;gt;::value &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; is_pointer_custom&amp;lt;int* volatile&amp;gt;::value &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; is_pointer_custom&amp;lt;int* const volatile&amp;gt;::value &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; is_pointer_custom&amp;lt;int* volatile const&amp;gt;::value &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>const</category>
      <category>const volatile</category>
      <category>constexpr</category>
      <category>is_array</category>
      <category>is_pointer</category>
      <category>template</category>
      <category>volatile</category>
      <category>템플릿</category>
      <category>템플릿 특수화</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/137</guid>
      <comments>https://devoops.tistory.com/137#entry137comment</comments>
      <pubDate>Sun, 3 Jan 2021 18:17:11 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 constexpr 함수(constexpr function)</title>
      <link>https://devoops.tistory.com/136</link>
      <description>&lt;p&gt;&lt;b&gt;constexpr 함수&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;함수앞에 constexpr 붙이면 파라미터가 컴파일 타임 상수 일 경우 함수를 컴파일 시간에 연산(성능 이점)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;일반 변수 파라미터 입력시 일반 함수처럼 동작&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609642584037&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;int N&amp;gt; struct Check
{

};

// constexpr 함수(c++11)
constexpr int add(int a, int b)
{
    return a + b;
}

int main()
{
    int n1 = 1, n2 = 2;

    int n = add(n1, n2);   // OK(일반 변수 파라미터 입력 시 일반 함수처럼 동작)
    int m = add(1, 2);     // OK(컴파일 타임 상수 파라미터 입력 시 컴파일 타임에 연산)
    Check&amp;lt;add(1, 2)&amp;gt; c;    // OK(컴파일 타임에 연산됨으로 템플릿 파라미터로 사용 가능)
    Check&amp;lt;add(n1, n2)&amp;gt; c2; // Error(일반 함수처럼 동작하므로 템플릿 파라미터로 사용 불가)
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>C++11</category>
      <category>constexpr</category>
      <category>constexpr function</category>
      <category>constexpr 함수</category>
      <category>template parameter</category>
      <category>컴파일 상수</category>
      <category>템플릿 파라미터</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/136</guid>
      <comments>https://devoops.tistory.com/136#entry136comment</comments>
      <pubDate>Sun, 3 Jan 2021 11:57:38 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 메타 프로그래밍(Template meta programming)</title>
      <link>https://devoops.tistory.com/135</link>
      <description>&lt;p&gt;&lt;b&gt;템플릿 메타 프로그래밍&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 시간에 연산을 수행하는 개념&lt;/li&gt;
&lt;li&gt;템플릿 파라미터 5를 받았을때 5 * 4 * 3 * 2 * 1 값을 반환하는 Factorial 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609638820843&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

//  템플릿 메타 프로그래밍(template meta programming)
template&amp;lt;int N&amp;gt; struct Factorial
{
    enum { value = N * Factorial&amp;lt;N-1&amp;gt;::value };
};

// 재귀의 종료를 위해 특수화(Specialization)
template&amp;lt;&amp;gt; struct Factorial&amp;lt;1&amp;gt;
{
    enum { value = 1 };
};

int main()
{

    int n = Factorial&amp;lt;5&amp;gt;::value; // 5 * 4 * 3 * 2 * 1 =&amp;gt; 120
    // 5 * Factorial&amp;lt;4&amp;gt;::value
    // 4 * Factorial&amp;lt;3&amp;gt;::value
    // 3 * Factorial&amp;lt;2&amp;gt;::value
    // 2 * Factorial&amp;lt;1&amp;gt;::value
    // 1

    cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;C++11 이후 부터는 enum대신 constexpr을 사용할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1609638886817&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

//  템플릿 메타 프로그래밍(template meta programming)
template&amp;lt;int N&amp;gt; struct Factorial
{
    //enum { value = N * Factorial&amp;lt;N-1&amp;gt;::value };
    static constexpr int value = N * Factorial&amp;lt;N - 1&amp;gt;::value;
};

// 재귀의 종료를 위해 특수화(Specialization)
template&amp;lt;&amp;gt; struct Factorial&amp;lt;1&amp;gt;
{
    //enum { value = 1 };
    static constexpr int value = 1;
};

int main()
{

    int n = Factorial&amp;lt;5&amp;gt;::value; // 5 * 4 * 3 * 2 * 1 =&amp;gt; 120
    // 5 * Factorial&amp;lt;4&amp;gt;::value
    // 4 * Factorial&amp;lt;3&amp;gt;::value
    // 3 * Factorial&amp;lt;2&amp;gt;::value
    // 2 * Factorial&amp;lt;1&amp;gt;::value
    // 1

    cout &amp;lt;&amp;lt; n &amp;lt;&amp;lt; endl;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>META Programming</category>
      <category>메타 프로그래밍</category>
      <category>템플릿 메타 프로그래밍</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/135</guid>
      <comments>https://devoops.tistory.com/135#entry135comment</comments>
      <pubDate>Sun, 3 Jan 2021 10:58:32 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 특수화 예제(Tuple)</title>
      <link>https://devoops.tistory.com/134</link>
      <description>&lt;p&gt;&lt;b&gt;XTuple(Couple 선형화 구현)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Couple 재귀 호출 대신 선형 호출 할 수 있는 패턴 지원
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;Couple&amp;lt;int, Couple&amp;lt;int, double&amp;gt;...&amp;gt; -&amp;gt; XTuple&amp;lt;int, int, double...&amp;gt; 형태로 개선&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Null 클래스 활용(Empty class)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;멤버 없는 클래스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;크기는 항상 1(sizeof(Null))&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;멤버는 없지만 타입이므로 함수 오버로딩이나 템플릿 인자로 활용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;상속 활용 기술&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;개수의 제한을 없앨 수 없을까? C+++ Variadic template&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609605148122&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

template&amp;lt;typename T, typename U&amp;gt; struct Couple
{
    T v1;
    U v2;

    enum { N = 2 };
};

// 빈 파라미터로 활용하기 위한 empty class
struct Null {};

// 2개이상 5개 미만의 타입전달
template&amp;lt;typename P1,
typename P2,
typename P3 = Null,
typename P4 = Null,
typename P5 = Null&amp;gt; 
class XTuple 
    : public Couple&amp;lt;P1, XTuple&amp;lt;P2, P3, P4, P5, Null&amp;gt;&amp;gt;
{

};

// XTuple 상속을 종료하기 위한 특수화
template&amp;lt;typename P1, typename P2&amp;gt;
class XTuple&amp;lt;P1, P2, Null, Null, Null&amp;gt;
    : public Couple&amp;lt;P1, P2&amp;gt;
{

};

int main()
{
    // Couple을 선형화하여 XTuple 형태로 사용
    XTuple&amp;lt;int, char, long, short, double&amp;gt; t5;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>Couple</category>
      <category>specialization</category>
      <category>template</category>
      <category>tuple</category>
      <category>xtuple</category>
      <category>선형호출</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/134</guid>
      <comments>https://devoops.tistory.com/134#entry134comment</comments>
      <pubDate>Sun, 3 Jan 2021 01:35:59 +0900</pubDate>
    </item>
    <item>
      <title>C++ 템플릿 특수화 예제(Couple)</title>
      <link>https://devoops.tistory.com/133</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Couple&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;2개의 인자로 받은 데이터를 보관하는 컨테이너&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;인자로 Couple 타입도 전달 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;부분 특수화(Partial specialization)를 할때 파라미터 수를 잘 선택해야함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;파라미터로 자기 자신을 재귀로 입력 시 N 표현 방법 고려&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;1번째 인자, 2번째 인자, 모든 인자가 Couple 일 경우 특수화 방법 고려&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1609602868755&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;type_traits&amp;gt;
using namespace std;

// 보관 데이터 수를 출력하는 함수
template&amp;lt;typename T&amp;gt; void printN(const T&amp;amp; cp)
{
    cout &amp;lt;&amp;lt; T::N &amp;lt;&amp;lt; endl;
}

// 2개의 인자를 보관하는 데이터(메인 템플릿)
template&amp;lt;typename T, typename U&amp;gt; struct Couple
{
    T v1;
    U v2;

    enum { N = 2 };
};

// 2번째 인자가 Couple일 경우
template&amp;lt;typename A, typename B, typename C&amp;gt;
struct Couple&amp;lt;A, Couple&amp;lt;B, C&amp;gt;&amp;gt;
{
    A v1;
    Couple&amp;lt;B, C&amp;gt; v2;
    enum { N = Couple&amp;lt;B, C&amp;gt;::N + 1 };
};

// 1번째 인자가 Couple일 경우
template&amp;lt;typename A, typename B, typename C&amp;gt;
struct Couple&amp;lt;Couple&amp;lt;A, B&amp;gt;, C&amp;gt;
{
    Couple&amp;lt;A, B&amp;gt; v1;
    C v2;
    enum { N = Couple&amp;lt;A, B&amp;gt;::N + 1 };
};

// 1번째, 2번째 모든 인자가 Couple일 경우
template&amp;lt;typename A, typename B, typename C, typename D&amp;gt;
struct Couple&amp;lt;Couple&amp;lt;A, B&amp;gt;, Couple&amp;lt;C, D&amp;gt;&amp;gt;
{
    Couple&amp;lt;A, B&amp;gt; v1;
    Couple&amp;lt;C, D&amp;gt; v2; 
    enum { N = Couple&amp;lt;A, B&amp;gt;::N + Couple&amp;lt;C, D&amp;gt;::N };
};

int main()
{
    // 2개의 인자 데이터
    Couple&amp;lt;int, double&amp;gt; c2;
    
    // 2번째 인자에 Couple 데이터를 입력 할 경우(총 3개 보관)
    // 가변 영역의 데이터는 int, int, char 총 3개
    Couple&amp;lt;int, Couple&amp;lt;int, char&amp;gt;&amp;gt; c3;
    
    // 2번째 인자의 Couple 데이터의 2번째 인자에 다시 Couple 데이터를 입력 할 경우(총 4개 보관)
    // Couple 데이터를 중첩하여 사용하였으나 가변 영역은 동일하게 int, int, T로 총 3개
    Couple&amp;lt;int, Couple&amp;lt;int, Couple&amp;lt;int, char&amp;gt;&amp;gt;&amp;gt; c4;
    
    // 1번째, 2번째 인자 모두 Couple 데이터를 입력 할 경우(총 4개 보관)
    Couple&amp;lt;Couple&amp;lt;int, int&amp;gt;, Couple&amp;lt;int, int&amp;gt;&amp;gt; c5;

    // 보관 데이터 수 출력
    printN(c2);
    printN(c3);
    printN(c4);
    printN(c5);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로그래밍 언어/C++</category>
      <category>C++</category>
      <category>Couple</category>
      <category>pair</category>
      <category>specialization</category>
      <category>template specialization</category>
      <category>부분 특수화</category>
      <category>템플릿 부분 특수화</category>
      <category>템플릿 특수화</category>
      <category>템플릿 특수화 예제</category>
      <category>특수화</category>
      <author>더해리</author>
      <guid isPermaLink="true">https://devoops.tistory.com/133</guid>
      <comments>https://devoops.tistory.com/133#entry133comment</comments>
      <pubDate>Sun, 3 Jan 2021 01:01:37 +0900</pubDate>
    </item>
  </channel>
</rss>