별칭 및 typedef(C++)

별칭 선언사용하여 이전에 선언된 형식의 동의어로 사용할 이름을 선언할 수 있습니다. (이 메커니즘은 비공식적으로 형식 별칭이라고 도 함). 이 메커니즘을 사용하여 사용자 지정 할당자에 유용할 수 있는 별칭 템플릿을 만들 수도 있습니다.

구문

using identifier = type;

설명

identifier
별칭 이름입니다.

type
별칭을 만드는 형식 식별자입니다.

별칭은 새 형식을 도입하지 않으며 기존 형식 이름의 의미를 변경할 수 없습니다.

가장 간단한 형태의 별칭은 C++03의 typedef 메커니즘과 동일합니다.

// C++11
using counter = long;

// C++03 equivalent:
// typedef long counter;

이러한 두 양식은 모두 형식 counter의 변수를 만들 수 있습니다. std::ios_base::fmtflags에 대해서는 이와 같은 형식 별칭이 더 유용합니다.

// C++11
using fmtfl = std::ios_base::fmtflags;

// C++03 equivalent:
// typedef std::ios_base::fmtflags fmtfl;

fmtfl fl_orig = std::cout.flags();
fmtfl fl_hex = (fl_orig & ~std::cout.basefield) | std::cout.showbase | std::cout.hex;
// ...
std::cout.flags(fl_hex);

별칭은 함수 포인터에서도 작동하지만 동등한 typedef보다 훨씬 더 읽기가 가능합니다.

// C++11
using func = void(*)(int);

// C++03 equivalent:
// typedef void (*func)(int);

// func can be assigned to a function pointer value
void actual_function(int arg) { /* some code */ }
func fptr = &actual_function;

메커니즘의 typedef 제한 사항은 템플릿에서 작동하지 않는다는 것입니다. 그러나 C++ 11의 형식 별칭 구문을 사용하면 별칭 템플릿을 만들 수 있습니다.

template<typename T> using ptr = T*;

// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> ptr_int;

예시

다음 예제에서는 사용자 지정 할당자(이 경우 정수 벡터 형식)와 별칭 템플릿을 사용하는 방법을 데모로 보여 줍니다. 모든 형식을 int 대체하여 편리한 별칭을 만들어 기본 함수 코드에서 복잡한 매개 변수 목록을 숨길 수 있습니다. 코드 전체에서 사용자 지정 할당자를 사용하면 가독성을 개선하고 오타로 인한 버그가 발생할 위험을 줄일 수 있습니다.

#include <stdlib.h>
#include <new>

template <typename T> struct MyAlloc {
    typedef T value_type;

    MyAlloc() { }
    template <typename U> MyAlloc(const MyAlloc<U>&) { }

    bool operator==(const MyAlloc&) const { return true; }
    bool operator!=(const MyAlloc&) const { return false; }

    T * allocate(const size_t n) const {
        if (n == 0) {
            return nullptr;
        }

        if (n > static_cast<size_t>(-1) / sizeof(T)) {
            throw std::bad_array_new_length();
        }

        void * const pv = malloc(n * sizeof(T));

        if (!pv) {
            throw std::bad_alloc();
        }

        return static_cast<T *>(pv);
    }

    void deallocate(T * const p, size_t) const {
        free(p);
    }
};

#include <vector>
using MyIntVector = std::vector<int, MyAlloc<int>>;

#include <iostream>

int main ()
{
    MyIntVector foov = { 1701, 1764, 1664 };

    for (auto a: foov) std::cout << a << " ";
    std::cout << "\n";

    return 0;
}
1701 1764 1664

Typedef

선언은 typedef 해당 범위 내에서 선언의 형식 선언 부분에서 지정된 형식의 동의어가 되는 이름을 소개합니다.

typedef 선언을 사용하여 언어로 이미 정의된 형식 또는 선언한 형식에 대해 더 짧거나 더 의미 있는 이름을 생성할 수 있습니다. typedef 이름을 사용하면 변경될 수 있는 구현 정보를 캡슐화할 수 있습니다.

선언은 class, struct, union및 선언 typedefenum 달리 새 형식을 도입하지 않으며 기존 형식에 대한 새 이름을 도입합니다.

선언 typedef 된 이름은 다른 식별자와 동일한 네임스페이스를 차지합니다(문 레이블 제외). 따라서 클래스 형식 선언을 제외하고 이전에 선언된 이름과 동일한 식별자를 사용할 수 없습니다. 다음 예제를 참조하세요.

// typedef_names1.cpp
// C2377 expected
typedef unsigned long UL;   // Declare a typedef name, UL.
int UL;                     // C2377: redefined.

다른 식별자와 관련된 이름 숨기기 규칙도 사용하여 typedef선언된 이름의 표시 유형을 제어합니다. 따라서 다음 예제는 C++에서 사용할 수 있습니다.

// typedef_names2.cpp
typedef unsigned long UL;   // Declare a typedef name, UL
int main()
{
   unsigned int UL;   // Redeclaration hides typedef name
}

// typedef UL back in scope

이름 숨기기의 또 다른 인스턴스:

// typedef_specifier1.cpp
typedef char FlagType;

int main()
{
}

void myproc( int )
{
    int FlagType;
}

동일한 이름으로 typedef로컬 범위 식별자를 선언하거나 동일한 범위 또는 내부 범위에서 구조체 또는 공용 구조체의 멤버를 선언할 때 형식 지정자를 지정해야 합니다. 예시:

typedef char FlagType;
const FlagType x;

식별자, 구조체 멤버 또는 공용 구조체 멤버에 FlagType 이름을 다시 사용하려면 형식을 제공해야 합니다.

const int FlagType;  // Type specifier required

말하는 것으로 충분하지 않은 이유는

const FlagType;      // Incomplete specification

다시 FlagType 선언되는 식별자가 아니라 형식의 일부로 사용되기 때문입니다. 이 선언은 다음과 유사한 잘못된 선언으로 처리됩니다.

int;  // Illegal declaration

포인터, 함수 및 배열 형식을 비롯한 모든 형식을 typedef를 사용하여 선언할 수 있습니다. 정의의 표시 유형이 선언의 표시 유형과 동일한 경우 구조체 또는 공용 구조체 형식을 정의하기 전에 구조체 또는 공용 구조체 형식에 대한 포인터의 typedef 이름을 선언할 수 있습니다.

예제

선언의 typedef 한 가지 사용은 선언을 보다 균일하고 간결하게 만드는 것입니다. 예시:

typedef char CHAR;          // Character type.
typedef CHAR * PSTR;        // Pointer to a string (char *).
PSTR strchr( PSTR source, CHAR target );
typedef unsigned long ulong;
ulong ul;     // Equivalent to "unsigned long ul;"

동일한 선언에서 기본 형식과 파생 형식을 지정하는 데 사용 typedef 하려면 선언자를 쉼표로 구분할 수 있습니다. 예시:

typedef char CHAR, *PSTR;

다음 예제에서는 값을 반환하지 않고 두 개의 int 인수를 사용하는 함수에 대한 DRAWF 형식을 제공합니다.

typedef void DRAWF( int, int );

위의 typedef 문 다음에 선언합니다.

DRAWF box;

다음 선언과 동일합니다.

void box( int, int );

typedef 는 사용자 정의 형식을 선언하고 이름을 지정하기 위해 결합 struct 되는 경우가 많습니다.

// typedef_specifier2.cpp
#include <stdio.h>

typedef struct mystructtag
{
    int   i;
    double f;
} mystruct;

int main()
{
    mystruct ms;
    ms.i = 10;
    ms.f = 0.99;
    printf_s("%d   %f\n", ms.i, ms.f);
}
10   0.990000

typedefs 다시 선언

이 선언은 typedef 동일한 형식을 참조하기 위해 동일한 이름을 다시 묶는 데 사용할 수 있습니다. 예시:

원본 파일 file1.h:

// file1.h
typedef char CHAR;

원본 파일 file2.h:

// file2.h
typedef char CHAR;

원본 파일 prog.cpp:

// prog.cpp
#include "file1.h"
#include "file2.h"   // OK

파일에 prog.cpp 는 두 개의 헤더 파일이 포함되며, 둘 다 이름CHAR에 대한 선언을 포함합니다typedef. 두 선언이 동일한 형식을 참조하는 한 이러한 재선언은 허용됩니다.

A typedef 는 이전에 다른 형식으로 선언된 이름을 다시 정의할 수 없습니다. 이 대안은 다음과 같습니다.file2.h

// file2.h
typedef int CHAR;     // Error

컴파일러는 다른 형식을 참조하기 위해 이름을 CHAR 다시 묶으려고 했기 때문에 오류를 prog.cpp 발생합니다. 이 정책은 다음과 같은 구문으로 확장됩니다.

typedef char CHAR;
typedef CHAR CHAR;      // OK: redeclared as same type

typedef union REGS      // OK: name REGS redeclared
{                       //  by typedef name with the
    struct wordregs x;  //  same meaning.
    struct byteregs h;
} REGS;

C++ 및 C의 typedef

선언에서 typedef 명명되지 않은 구조를 typedef 선언하는 ANSI C 사례로 인해 클래스 형식과 함께 지정자의 사용이 주로 지원됩니다. 예를 들어 많은 C 프로그래머는 다음 관용구를 사용합니다.

// typedef_with_class_types1.cpp
// compile with: /c
typedef struct {   // Declare an unnamed structure and give it the
                   // typedef name POINT.
   unsigned x;
   unsigned y;
} POINT;

이러한 선언의 장점은 다음과 같은 선언이 가능하다는 것입니다.

POINT ptOrigin;

위의 선언을 아래의 선언 대신 사용할 수 있습니다.

struct point_t ptOrigin;

C++에서는 이름과 실제 형식(, , structunionenum 키워드(keyword)으로 선언됨class)의 차이가 typedef 더 뚜렷합니다. 문에서 typedef 이름 없는 구조를 선언하는 C 사례는 여전히 작동하지만 C에서와 마찬가지로 표기법상의 이점을 제공하지 않습니다.

// typedef_with_class_types2.cpp
// compile with: /c /W1
typedef struct {
   int POINT();
   unsigned x;
   unsigned y;
} POINT;

앞의 예제에서는 명명되지 않은 클래스 구문을 사용하여 명명 POINT 된 클래스 typedef 를 선언합니다. POINT는 클래스 이름으로 간주되지만 다음과 같은 제한 사항이 이런 방식으로 생성된 이름에 적용됩니다.

  • 이름(동의어)은 , struct또는 union 접두사 뒤를 class표시할 수 없습니다.

  • 이 이름은 클래스 선언 내에서 생성자 또는 소멸자 이름으로 사용할 수 없습니다.

요약하자면, 이 구문은 상속, 생성 또는 소멸을 위한 메커니즘을 제공하지 않습니다.