エイリアスと typedef (C++)Aliases and typedefs (C++)

使用することができます、エイリアス宣言以前に宣言された型のシノニムとして使用する名前を宣言します。You can use an alias declaration to declare a name to use as a synonym for a previously declared type. (このメカニズムは、別名非公式、型の別名)。(This mechanism is also referred to informally as a type alias). このメカニズムを使用して作成する、エイリアス テンプレート、カスタム アロケーターに特に便利ですがあることができます。You can also use this mechanism to create an alias template, which can be particularly useful for custom allocators.

構文Syntax

using identifier = type;

RemarksRemarks

identifieridentifier
エイリアスの名前。The name of the alias.

typetype
エイリアスを作成する型識別子。The type identifier you are creating an alias for.

エイリアスでは新しい型は定義されず、既存の型名の意味を変更することはできません。An alias does not introduce a new type and cannot change the meaning of an existing type name.

エイリアスの最も単純な形式は、 typedef c++ 03 のメカニズム。The simplest form of an alias is equivalent to the typedef mechanism from C++03:

// C++11
using counter = long;

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

いずれの形式でも "カウンター" 型の変数を作成できます。Both of these enable the creation of variables of type "counter". 次のような std::ios_base::fmtflags の型エイリアスが便利な場合があります。Something more useful would be a type alias like this one for 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 よりもずっと読みは。Aliases also work with function pointers, but are much more readable than the equivalent 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メカニズムは、テンプレートを使用しないことです。A limitation of the typedef mechanism is that it doesn't work with templates. しかし、C++11 での型エイリアスの構文ではエイリアス テンプレートを作成できます。However, the type alias syntax in C++11 enables the creation of alias templates:

template<typename T> using ptr = T*;

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

Example

次の例に、エイリアス テンプレートをカスタム アロケーター (この場合は整数ベクター型) で使用する方法を示します。The following example demonstrates how to use an alias template with a custom allocator—in this case, an integer vector type. 任意の型を置き換えることができるint主要な機能コードのリストを複合型のパラメーターを非表示にする便利なエイリアスを作成します。You can substitute any type for int to create a convenient alias to hide the complex parameter lists in your main functional code. コード全体でカスタム アロケーターを使用することで読みやすくして、入力ミスによるバグが発生するリスクを減らすことができます。By using the custom allocator throughout your code you can improve readability and reduce the risk of introducing bugs caused by typos.

#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

TypedefTypedefs

A typedef宣言に名前をそのスコープの中で指定した型のシノニムになりますが導入されています、型宣言宣言の一部です。A typedef declaration introduces a name that, within its scope, becomes a synonym for the type given by the type-declaration portion of the declaration.

typedef 宣言を使用して、既に言語で定義されている型や、宣言した型に対して、より短い、またはわかりやすい名前を作成できます。You can use typedef declarations to construct shorter or more meaningful names for types already defined by the language or for types that you have declared. Typedef 名を使用して、変更可能な実装の詳細をカプセル化できます。Typedef names allow you to encapsulate implementation details that may change.

異なり、クラス構造体共用体、およびenum宣言、 typedef宣言は新しい型を導入していません-既存の型の新しい名前を導入します。In contrast to the class, struct, union, and enum declarations, typedef declarations do not introduce new types — they introduce new names for existing types.

使用して宣言された名前typedef (ステートメント ラベル) を除くその他の識別子と同じ名前空間を占有します。Names declared using typedef occupy the same namespace as other identifiers (except statement labels). したがって、クラス型の宣言以外では、以前に宣言された名前と同じ識別子を使用できません。Therefore, they cannot use the same identifier as a previously declared name, except in a class-type declaration. 次に例を示します。Consider the following example:

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

その他の識別子に関連する名前隠蔽規則も使用して宣言された名前の可視性を管理typedefします。The name-hiding rules that pertain to other identifiers also govern the visibility of names declared using typedef. したがって、次の例は C++ で有効です。Therefore, the following example is legal in 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 と同じ名前でローカル スコープの識別子を宣言するとき、あるいは同じスコープまたは内部スコープで構造体または共用体のメンバーを宣言するときは、型指定子を指定する必要があります。When declaring a local-scope identifier by the same name as a typedef, or when declaring a member of a structure or union in the same scope or in an inner scope, the type specifier must be specified. 例えば:For example:

typedef char FlagType;
const FlagType x;

識別子、構造体メンバー、または共用体メンバーに対して FlagType 名を再利用するには、次のように型を指定する必要があります。To reuse the FlagType name for an identifier, a structure member, or a union member, the type must be provided:

const int FlagType;  // Type specifier required

次のような記述だけでは不十分です。It is not sufficient to say

const FlagType;      // Incomplete specification

FlagType は再宣言された識別子ではなく、型の一部であると見なされるためです。because the FlagType is taken to be part of the type, not an identifier that is being redeclared. この宣言は、次のような正しくない宣言であると見なされます。This declaration is taken to be an illegal declaration like

int;  // Illegal declaration

ポインター、関数、配列型を含め、あらゆる型を typedef で宣言できます。You can declare any type with typedef, including pointer, function, and array types. 構造体型または共用体型を定義する前に、構造体型または共用体型へのポインターの typedef 名を宣言できます。ただし、定義が宣言と同じ可視性である必要があります。You can declare a typedef name for a pointer to a structure or union type before you define the structure or union type, as long as the definition has the same visibility as the declaration.

使用例Examples

用途の 1 つtypedef宣言より同型でコンパクトな宣言を作成します。One use of typedef declarations is to make declarations more uniform and compact. 例えば:For example:

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同じ宣言内には、基本と派生型を指定するにはコンマで宣言子を分離することができます。To use typedef to specify fundamental and derived types in the same declaration, you can separate declarators with commas. 例:For example:

typedef char CHAR, *PSTR;

次の例は、値を返さず、2 つの int 引数を受け取る関数に対する型 DRAWF を用意します。The following example provides the type DRAWF for a function returning no value and taking two int arguments:

typedef void DRAWF( int, int );

上記の後にtypedefステートメントでは、宣言After the above typedef statement, the declaration

DRAWF box;

は次の宣言と同等です。would be equivalent to the declaration

void box( int, int );

typedef多くの場合、組み合わせる構造体を宣言し、ユーザー定義型の名前します。typedef is often combined with struct to declare and name user-defined types:

// 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

typedef の再宣言Re-declaration of typedefs

Typedef宣言を同じ型を参照する同じ名前を再宣言して使用できます。The typedef declaration can be used to redeclare the same name to refer to the same type. 例えば:For example:

// FILE1.H
typedef char CHAR;

// FILE2.H
typedef char CHAR;

// PROG.CPP
#include "file1.h"
#include "file2.h"   // OK

プログラムPROG します。CPP両方が含まれている 2 つのヘッダー ファイルが含まれますtypedef名の宣言CHARします。The program PROG.CPP includes two header files, both of which contain typedef declarations for the name CHAR. 両方の宣言が同じ型を参照する限り、このような再宣言は許容されます。As long as both declarations refer to the same type, such redeclaration is acceptable.

A typedefは以前に異なる型として宣言する名前を再定義できません。A typedef cannot redefine a name that was previously declared as a different type. そのため場合、 FILE2 します。Hが含まれていますTherefore, if FILE2.H contains

// FILE2.H
typedef int CHAR;     // Error

コンパイラは、名前 CHAR を再宣言して異なる型を参照しようとするため、エラーが発生します。the compiler issues an error because of the attempt to redeclare the name CHAR to refer to a different type. このことは、次のような構造もに及びます。This extends to constructs such as:

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;

typedef: C++ と Ctypedefs in C++ vs. C

使用、 typedefで名前のない構造体を宣言する ANSI C プラクティスのため大きく指定子がクラス型がサポートされているtypedef宣言します。Use of the typedef specifier with class types is supported largely because of the ANSI C practice of declaring unnamed structures in typedef declarations. たとえば、多くの C プログラマは次のように記述します。For example, many C programmers use the following:

// 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;

このような宣言の利点は、次のような宣言を使用できることです。The advantage of such a declaration is that it enables declarations like:

POINT ptOrigin;

次のように記述する必要がありません。instead of:

struct point_t ptOrigin;

C++ では、間の差typedef名と実際の型 (で宣言された、クラス構造体共用体、およびenumキーワード) がより明確です。In C++, the difference between typedef names and real types (declared with the class, struct, union, and enum keywords) is more distinct. C の実習で無名の構造体を宣言するをtypedefステートメントが機能、その利点はなく表記 C. では、Although the C practice of declaring a nameless structure in a typedef statement still works, it provides no notational benefits as it does in C.

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

前の例は、という名前のクラスを宣言します。POINT名前のないクラスを使用してtypedef構文。The preceding example declares a class named POINT using the unnamed class typedef syntax. POINT はクラス名として扱われますが、この方法で導入された名前には次の制限が適用されます。POINT is treated as a class name; however, the following restrictions apply to names introduced this way:

  • 名前 (シノニム) が後に表示されることはできません、クラス構造体、または共用体プレフィックス。The name (the synonym) cannot appear after a class, struct, or union prefix.

  • 名前は、クラス宣言内のコンストラクター名またはデストラクター名として使用できません。The name cannot be used as constructor or destructor names within a class declaration.

つまり、この構文には、継承、構築、または破棄のための機能はありません。In summary, this syntax does not provide any mechanism for inheritance, construction, or destruction.