기능 | typedef | using |
---|---|---|
사용자 정의 타입에 새로운 이름 부여 | O | O |
별칭 템플릿 가능 | X | O |
#include <memory>
#include <unordered_map>
#include <string>
// 새로운 이름 부여
// typedef
typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
// alias declaration
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
// 함수 포인터
// typedef
typedef void (*FP)(int, const std::string&);
// alias declaration
using FP = void (*)(int, const std::string&);
// 템플릿
// typedef는 템플릿화 불가
// alias declaration
class Widget{};
template<typename T>
using MyAllocList = std::list<T, MyAlloc<T>>;
MyAllocList<Widget> lw; // std::list<Widget, MyAlloc<Widget>> lw; 와 동일
일반적으로 중괄호 쌍 안에서 어떤 이름을 선언하면 그 이름의 가시성은 해당 중괄호 쌍이 정의하는 범위로 한정됨
그런데 C++98 스타일의 enum은 그러한 일반적인 규칙이 적용되지 않음
enum을 포함하는 범위에 속하게 되며 해당 범위 내 같은 이름이 존재하면 안 됨
=> 이러한 특성 때문에 범위 없는 enum이라고 부름
enum Color { black, white, red };
auto white = false; // 오류 범위 내에 이미 white이 있음
암묵적으로 다른 형식으로 변환됨
enum Color { black, white, red };
std::vector<std::size_t> primeFactors(std::size_t x);
Color c = red;
if ( c < 14.5 )
{
auto factors = primeFactors(c);
}
C++11부터는 이름 없는 enum도 전방 선언이 가능함
C++11의 새로운 열거형인 범위 있는 enum은 그러한 이름 누수가 발생되지 않음
암묵적으로 다른 형식으로 변환되지 않음
전방 선언이 가능함
바탕 형식을 지정할 수 있음
enum class Color { black, white, red };
auto white = false; // OK
Color a = white; // 오류 범위 있는 enum은 정수형으로 변환 X
Color b = Color::white; // OK
auto c = Color::white; // OK
enum class Color { black, white, red };
std::vector<std::size_t> primeFactors(std::size_t x);
Color c = Color::red;
if (c < 14.5) // 오류 Color와 double 비교 불가
{
auto factors = primeFactors(c); // 오류 std::size_t를 기대하는 함수에 Color 전달 불가
}
// 만약 다른 형식으로 변환하고 싶다면 캐스팅을 해야함
if (static_cast<double>(c) < 14.5)
{
auto factors = primeFactors(static_cast<std::size_t>(c));
}
전방 선언이 가능하기 때문에 열거자들을 지정하지 않고 열거형 이름만 미리 선언 가능
enum Color; // C++98기준 오류 C++11부터는 가능
enum class Color; // OK
기본 바탕 형식은 int이지만 다른 형식을 명시적으로 지정할 수 있음
enum class Status: std::uint32_t;
튜플 안에 있는 필드들을 지칭할 때 유용함
// 정수를 사용하는 경우 -> 1번 필드가 뭔지 기억하기 어려움
using UserInfo = std::tuple<std::string, std::string, std::size_t>;
UserInfo uInfo;
auto val = std::get<1>(uInfo);
// 범위 없는 enum 사용 -> 명확히 어떤 필드를 가져오는건지 알 수 있음
enum UserInfoFields { uiName, uiEmail, uiReputation };
auto val = std::get<uiEmail>(uInfo); // 암묵적 형변환이 가능하기 때문
// 만약 범위 있는 enum을 사용한다면 캐스팅을 하거나
enum class UserInfoFields { uiName, uiEmail, uiReputation };
auto val = std::get<static_cast<std::size_t>(UserInfoFields::uiEmail)>(uInfo);
// 함수를 만들어야 함
// 변환하는 함수는 컴파일 시점에 산출해야 하므로 constexpr 함수여야 함
// 어떤 종류에도 동작하기 위해서는 함수 템플릿 형태여야 하며
// 예외를 던지지 않을 것이므로 noexcept로 선언해야 함
template<typename E>
constexpr auto toUType(E enumerator) noexcept
{
return static_cast<typename std::underlying_type<E>::type>(enumerator);
}
auto val = std::get<toUType(UserInfoFields::uiEmail)>(uInfo);