ShovelingLife
A Game Programmer
ShovelingLife
전체 방문자
오늘
어제
  • 분류 전체보기 (1074)
    • 그래픽스 (57)
      • 공통 (19)
      • 수학 물리 (22)
      • OpenGL & Vulkan (1)
      • DirectX (14)
    • 게임엔진 (183)
      • Unreal (69)
      • Unity (103)
      • Cocos2D-X (3)
      • 개인 플젝 (8)
    • 코딩테스트 (221)
      • 공통 (7)
      • 프로그래머스 (22)
      • 백준 (162)
      • LeetCode (19)
      • HackerRank (2)
      • 코딩테스트 알고리즘 (8)
    • CS (235)
      • 공통 (21)
      • 네트워크 (44)
      • OS & 하드웨어 (55)
      • 자료구조 & 알고리즘 (98)
      • 디자인패턴 (6)
      • UML (4)
      • 데이터베이스 (7)
    • 프로그래밍 언어 (349)
      • C++ (168)
      • C# (90)
      • Java (9)
      • Python (33)
      • SQL (30)
      • JavaScript (8)
      • React (7)
    • 그 외 (10)
      • Math (5)
      • 일상 (5)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • Source Code 좌측 상단에 복사 버튼 추가 완료
  • 언리얼 엔진 C++ 빌드시간 단축 꿀팁
  • 게임 업계 코딩테스트 관련
  • 1인칭 시점으로 써내려가는 글들

인기 글

태그

  • 그래픽스
  • 알고리즘
  • string
  • C
  • 배열
  • SQL
  • 백준
  • C++
  • 티스토리챌린지
  • 프로그래머스
  • 유니티
  • 언리얼
  • 오블완
  • Unity
  • 클래스
  • 포인터
  • 함수
  • 문자열
  • 파이썬
  • c#

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
ShovelingLife

A Game Programmer

프로그래밍 언어/C++

C++ if/switch statement with initializer

2022. 12. 11. 23:32

0. 서문

지금까지의 C++에서 if 또는 switch의 평가식에 사용되는 변수는 미리 선언되고 적절히 초기화된 상태여야 한다.
std::map에 원소를 추가하고 이에 대한 예외 처리를 하는 아래 예제가 일반적인 샘플이라 할 수 있다.
#include <iostream>
#include <map>
 
int main()
{
    std::map<std::string, int> map;
    map["hello"] = 1;
    map["world"] = 2;
 
    // 일단 insert를 수행하고 결과 pair를 반환받아야 한다.
    auto ret = map.insert({ "hello", 3 });
 
    // 그러고 나서, pair의 2번째 요소를 체크
    if (!ret.second)
        std::cout << "hello already exists with value " << ret.first->second << "\n";
 
    // 한번 더 insert를 하려고 봤더니 이미 "ret"라는 변수명이 있기에 "ret2" 변수 명명 -_-;
    auto ret2 = map.insert({ "foo", 4 });
 
    // ret2에 대해서도 다시 체크
    if (!ret2.second)
        std::cout << "foo already exists with value " << ret2.first->second << "\n";
 
    return 0;
}
삽입을 할 때마다 결과값을 받기 위한 변수를 선언하고, 이후 이 변수의 값을 체크해야 하였다.
즉, if/switch가 평가해야 하는 변수가 미리 준비되어 있어야 했던 것이다.
이를 개선시키기 위해 C++17에서 if/switch 절에서 평가 대상을 초기화하고 즉시 평가할 수 있도록 변경되었다.

1. if w/ initializer

if statement with initializer의 syntax는 다음과 같다. (switch도 동일한 형태)
// initializing
// condition
if (initializing; condition)
{
}
if 절 내부에서 초기화를 할 수 있고 평가할 수 있으며, 초기화와 평가문은 semicolon(;)으로 구분짓는다.
서문의 예제를 if statement with initializer 방식으로 다시 풀어내면 다음과 같다.
#include <iostream>
#include <map>
 
int main()
{
    std::map<std::string, int> map;
    map["hello"] = 1;
    map["world"] = 2;
 
    // 평가 대상을 초기화하고, 즉시 평가한다.
    // "ret"는 if로부터 비롯된 평가절 내부에서만 유효하다.
    if (auto ret = map.insert({ "hello", 3 }); !ret.second)
        std::cout << "hello already exists with value " << ret.first->second << "\n";
 
    // 첫번째 insert의 "ret"는 첫번째 if 평가절 내부에서만 유효했기에 다시 사용해도 무방
    if (auto ret = map.insert({ "foo", 4 }); !ret.second)
        std::cout << "foo already exists with value " << ret.first->second << "\n";
 
    return 0;
}
핵심은 "해당 if 구문절에서만 필요한 변수의 scope를 해당 if 구문절 내부로 한정짓는다"가 될 것이다.
참고로, 위 예제를 C++17 Structured binding으로 살짝 변형시키면 다음과 같다.
 
#include <iostream>
#include <map>
 
int main()
{
    std::map<std::string, int> map;
    map["hello"] = 1;
    map["world"] = 2;
 
    // map::insert의 반환 형식 std::pair<iterator, bool>
    if (auto [it, success] = map.insert({ "hello", 3 }); !success)
        std::cout << "hello already exists with value " << it->second << "\n";

    if (auto [it, success] = map.insert({ "foo", 4 }); !success)
        std::cout << "foo already exists with value " << it->second << "\n";
 
    return 0;
}

2. switch w/ initializer

if의 그것과 완전히 동일한 형식을 가지기에 별도의 설명없이 예제만 추가한다.

#include <iostream>
 
enum Result
{
    SUCCESS,
    DEVICE_FULL,
    ABORTED
};
 
std::pair<size_t/*bytes*/, Result> writePacket()
{
    return { 100, SUCCESS };
}
 
int main()
{
/* C++ 14
    // 결과를 담을 "res" 변수를 마련한다. 당연히 main 함수의 scope를 가진다
    auto res = writePacket();
    // 평가
    switch (res.second)
*/
 
    // C++ 17. "res" 변수는 switch 절 scope를 가진다.
    switch (auto res = writePacket(); res.second)
    {
        case SUCCESS:
            std::cout << "successfully wrote " << res.first << " bytes\n";
            break;
        case DEVICE_FULL:
            std::cout << "insufficient space on device\n";
            break;
        case ABORTED:
            std::cout << "operation aborted before completion\n";
            break;
    }
 
    // switch scope가 끝났기에 아래 코드에서 컴파일 에러 발생
    if (res.second == SUCCESS)
        // Do something...
 
    return 0;
}

출처 : 수까락의 프로그래밍 이야기 (zum.com)

저작자표시 (새창열림)

'프로그래밍 언어 > C++' 카테고리의 다른 글

C++ 클래스 템플릿에 선언된 friend 함수를 외부에 정의하는 방법  (0) 2023.01.03
C/C++ 예외상황에서의 포인터의 동작  (0) 2022.12.17
C++ 모듈 (Module)  (0) 2022.11.30
C언어로 객체지향 주 4개의 요소 (추상화,다형성,상속,캡슐화) 구현하기  (0) 2022.11.26
C++ call by value, call by reference  (0) 2022.11.17
    '프로그래밍 언어/C++' 카테고리의 다른 글
    • C++ 클래스 템플릿에 선언된 friend 함수를 외부에 정의하는 방법
    • C/C++ 예외상황에서의 포인터의 동작
    • C++ 모듈 (Module)
    • C언어로 객체지향 주 4개의 요소 (추상화,다형성,상속,캡슐화) 구현하기
    ShovelingLife
    ShovelingLife
    Main skill stack => Unity C# / Unreal C++ Studying Front / BackEnd, Java Python

    티스토리툴바