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;
}
'프로그래밍 언어 > 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 |