Skip to content

Latest commit

 

History

History
362 lines (258 loc) · 9.75 KB

aliases-and-typedefs-cpp.md

File metadata and controls

362 lines (258 loc) · 9.75 KB
descriptiontitlems.datef1_keywordsms.assetid
Learn more about: Aliases and typedefs (C++)
Aliases and typedefs (C++)
06/30/2022
typedef_cpp
af1c24d2-4bfd-408a-acfc-482e264232f5

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 useful for custom allocators.

Syntax

using identifier = type;

Remarks

identifier
The name of the alias.

type
The type identifier you're creating an alias for.

An alias doesn't introduce a new type and can't change the meaning of an existing type name.

The simplest form of an alias is equivalent to the typedef mechanism from C++03:

// C++11using counter = long; // C++03 equivalent:// typedef long counter;

Both of these forms enable the creation of variables of type counter. Something more useful would be a type alias like this one for std::ios_base::fmtflags:

// C++11using 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);

Aliases also work with function pointers, but are much more readable than the equivalent typedef:

// C++11using func = void(*)(int); // C++03 equivalent:// typedef void (*func)(int);// func can be assigned to a function pointer valuevoidactual_function(int arg) { /* some code */ } func fptr = &actual_function;

A limitation of the typedef mechanism is that it doesn't work with templates. 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. 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> structMyAlloc { typedef T value_type; MyAlloc() { } template <typename U> MyAlloc(const MyAlloc<U>&) { } booloperator==(const MyAlloc&) const { returntrue; } booloperator!=(const MyAlloc&) const { returnfalse; } T * allocate(constsize_t n) const { if (n == 0) { returnnullptr; } if (n > static_cast<size_t>(-1) / sizeof(T)) { throwstd::bad_array_new_length(); } void * const pv = malloc(n * sizeof(T)); if (!pv) { throwstd::bad_alloc(); } returnstatic_cast<T *>(pv); } voiddeallocate(T * const p, size_t) const { free(p); } }; #include<vector>using MyIntVector = std::vector<int, MyAlloc<int>>; #include<iostream>intmain () { MyIntVector foov = { 1701, 1764, 1664 }; for (auto a: foov) std::cout << a << ""; std::cout << "\n"; return0; }
1701 1764 1664 

Typedefs

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.

You can use typedef declarations to construct shorter or more meaningful names for types already defined by the language or for types that you've declared. Typedef names allow you to encapsulate implementation details that may change.

In contrast to the class, struct, union, and enum declarations, typedef declarations don't introduce new types; they introduce new names for existing types.

Names declared using typedef occupy the same namespace as other identifiers (except statement labels). Therefore, they can't use the same identifier as a previously declared name, except in a class-type declaration. Consider the following example:

// typedef_names1.cpp// C2377 expectedtypedefunsignedlong UL; // Declare a typedef name, UL.int UL; // C2377: redefined.

The name-hiding rules that pertain to other identifiers also govern the visibility of names declared using typedef. Therefore, the following example is legal in C++:

// typedef_names2.cpptypedefunsignedlong UL; // Declare a typedef name, ULintmain() { unsignedint UL; // Redeclaration hides typedef name } // typedef UL back in scope

Another instance of name hiding:

// typedef_specifier1.cpptypedefchar FlagType; intmain() { } voidmyproc( int ) { int FlagType; }

When you declare a local-scope identifier by the same name as a typedef, or when you declare a member of a structure or union in the same scope or in an inner scope, the type specifier must be specified. For example:

typedefchar FlagType; const FlagType x;

To reuse the FlagType name for an identifier, a structure member, or a union member, the type must be provided:

constint FlagType; // Type specifier required

It isn't sufficient to say

const FlagType; // Incomplete specification

because the FlagType is taken to be part of the type, not an identifier that's being redeclared. This declaration is taken to be an illegal declaration, similar to:

int; // Illegal declaration

You can declare any type with typedef, including pointer, function, and array types. 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

One use of typedef declarations is to make declarations more uniform and compact. For example:

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

To use typedef to specify fundamental and derived types in the same declaration, you can separate declarators with commas. For example:

typedefchar CHAR, *PSTR;

The following example provides the type DRAWF for a function returning no value and taking two int arguments:

typedefvoidDRAWF( int, int );

After the above typedef statement, the declaration

DRAWF box;

would be equivalent to the declaration

voidbox( int, int );

typedef is often combined with struct to declare and name user-defined types:

// typedef_specifier2.cpp #include<stdio.h>typedefstructmystructtag { int i; double f; } mystruct; intmain() { mystruct ms; ms.i = 10; ms.f = 0.99; printf_s("%d %f\n", ms.i, ms.f); }
10 0.990000 

Redeclaration of typedefs

The typedef declaration can be used to redeclare the same name to refer to the same type. For example:

Source file file1.h:

// file1.htypedefchar CHAR;

Source file file2.h:

// file2.htypedefchar CHAR;

Source file prog.cpp:

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

The file 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 can't redefine a name that was previously declared as a different type. Consider this alternative file2.h:

// file2.htypedefint CHAR; // Error

The compiler issues an error in prog.cpp because of the attempt to redeclare the name CHAR to refer to a different type. This policy extends to constructs such as:

typedefchar CHAR; typedef CHAR CHAR; // OK: redeclared as same typetypedefunion REGS // OK: name REGS redeclared { // by typedef name with thestructwordregs x; // same meaning.structbyteregs h; } REGS;

typedefs in C++ vs. C

Use of the typedef specifier with class types is supported largely because of the ANSI C practice of declaring unnamed structures in typedef declarations. For example, many C programmers use the following idiom:

// typedef_with_class_types1.cpp// compile with: /ctypedefstruct { // 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:

structpoint_t ptOrigin;

In C++, the difference between typedef names and real types (declared with the class, struct, union, and enum keywords) is more distinct. 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 /W1typedefstruct { intPOINT(); unsigned x; unsigned y; } POINT;

The preceding example declares a class named POINT using the unnamed class typedef syntax. POINT is treated as a class name; however, the following restrictions apply to names introduced this way:

  • The name (the synonym) can't appear after a class, struct, or union prefix.

  • The name can't be used as a constructor or destructor name within a class declaration.

In summary, this syntax doesn't provide any mechanism for inheritance, construction, or destruction.

close