typedef, using, enum

·2024년 12월 10일
0

C++

목록 보기
20/26

typedef보다 별칭 선언을 선호하라

typedef, 별칭 선언(alias declaration)

기능typedefusing
사용자 정의 타입에 새로운 이름 부여OO
별칭 템플릿 가능XO
#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; 와 동일

범위 없는 enum보다 범위 있는 enum을 선호하라

범위 없는 enum

일반적으로 중괄호 쌍 안에서 어떤 이름을 선언하면 그 이름의 가시성은 해당 중괄호 쌍이 정의하는 범위로 한정됨
그런데 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도 전방 선언이 가능함

범위 있는 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;

범위 없는 enum은 언제 쓸까?

튜플 안에 있는 필드들을 지칭할 때 유용함

// 정수를 사용하는 경우 -> 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);

0개의 댓글

관련 채용 정보