C++/C++11中用于定义类型别名的两种方法:typedef和using
類型別名(type alias)是一個(gè)名字,它是某種類型的同義詞。使用類型別名有很多好處,它讓復(fù)雜的類型名字變得簡(jiǎn)單明了、易于理解和使用,還有助于程序員清楚地知道使用該類型的真實(shí)目的。在C++中,任何有效類型都可以有別名。
有兩種方法可用于定義類型別名:傳統(tǒng)的方法是使用關(guān)鍵字typedef;C++11中規(guī)定了一種新的方法,使用別名聲明(alias declaration)來(lái)定義類型的別名,即使用using.
關(guān)鍵字typedef作為聲明語(yǔ)句中的基本數(shù)據(jù)類型的一部分出現(xiàn)。含有typedef的聲明語(yǔ)句定義的不再是變量而是類型別名。和以前的聲明語(yǔ)句一樣,這里的聲明符也可以包含類型修飾,從而也能由基本數(shù)據(jù)類型構(gòu)造出復(fù)合類型來(lái)。
C++11中用關(guān)鍵字using作為別名聲明的開(kāi)始,其后緊跟別名和等號(hào),其作用是把等號(hào)左側(cè)的名字規(guī)定成等號(hào)右側(cè)類型的別名。
類型別名和類型的名字等價(jià),只要是類型的名字能出現(xiàn)的地方,就能使用類型別名。
如果某個(gè)類型別名指代的是復(fù)合類型或常量,那么把它用到聲明語(yǔ)句里就會(huì)產(chǎn)生意想不到的后果。
使用typedef定義的別名和使用using定義的別名在語(yǔ)義上是等效的。 唯一的區(qū)別是typedef在模板中有一定的局限性,而using沒(méi)有。
盡管typedef具有更長(zhǎng)的歷史記錄并且在現(xiàn)有代碼中可能更常見(jiàn),但using更通用。
無(wú)論是typedef還是using,它們都不會(huì)創(chuàng)建新的數(shù)據(jù)類型,它們僅僅創(chuàng)建現(xiàn)有類型的同義詞(synonyms)。不能用于更改現(xiàn)有類型名稱的含義。
typedef和using標(biāo)識(shí)符可以聲明數(shù)組和函數(shù)類型,指針和引用,類類型等等。但不能與任何其它標(biāo)識(shí)符組合使用。僅在它們可見(jiàn)的范圍內(nèi)有效:不同的函數(shù)或類聲明可以定義具有不同含義的相同名字的類型。
typedef的用法包括:定義一種類型的別名;用于struct聲明;用來(lái)定義與平臺(tái)無(wú)關(guān)的類型;用于回調(diào)函數(shù);為復(fù)雜的聲明定義一個(gè)新的簡(jiǎn)單的別名。
typedef是定義了一種類型的新別名,不同于宏,并不是簡(jiǎn)單的字符串替換。當(dāng)const和typedef一起出現(xiàn)時(shí),typedef不是簡(jiǎn)單的字符串替換:
注意:typedef int* INT; const INT p;相當(dāng)于int* const p;而不是const int* p;
在使用typedef時(shí),不能在聲明中有多個(gè)存儲(chǔ)類關(guān)鍵字:ypedef就像auto,extern, mutable, static, register一樣,是一個(gè)存儲(chǔ)類關(guān)鍵字。即typedef中不能出現(xiàn)這些關(guān)鍵字。
下面是從其他文章中copy的測(cè)試代碼,詳細(xì)內(nèi)容介紹可以參考對(duì)應(yīng)的reference:
typedef.cpp內(nèi)容如下:
#include "typedef.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <ios>
#include <type_traits>
#include <typeinfo>namespace typedef_ {///
// reference: https://en.cppreference.com/w/cpp/language/typedef// std::add_const, like many other metafunctions, use member typedefs
template< class T>
struct add_const {typedef const T type;
};int test_typedef_1()
{// simple typedeftypedef unsigned long ulong;// the following two objects have the same typeunsigned long l1;ulong l2;// more complicated typedeftypedef int int_t, *intp_t, (&fp)(int, ulong), arr_t[10];// the following two objects have the same typeint a1[10];arr_t a2;for (int i = 0; i < 10; ++i)a2[i] = i;for (int i = 0; i < 10; ++i)fprintf(stdout, "a2 value: %d\n", a2[i]);// common C idiom to avoid having to write "struct S"typedef struct {int a; int b;} S, *pS;// the following two objects have the same typepS ps1;S* ps2;// error: storage-class-specifier cannot appear in a typedef declaration// typedef static unsigned int uint;// typedef can be used anywhere in the decl-specifier-seqlong unsigned typedef int long ullong;// more conventionally spelled "typedef unsigned long long int ullong;"// std::add_const, like many other metafunctions, use member typedefs/*template< class T>struct add_const { // error: a template declaration cannot appear at block scopetypedef const T type;};*/typedef struct Node {//struct listNode* next; // declares a new (incomplete) struct type named listNode} listNode; // error: conflicts with the previously declared struct namestruct Node2 {int data;struct Node2* nextptr;};// 使用typedef可以將上面的Node2改寫為:typedef struct Node3 Node3;struct Node3 {int data;Node3* nextptr;};typedef double wages; // wages是double的同義詞typedef wages base, *p; // base是double的同義詞,p是double*的同義詞return 0;
}// reference: http://www.cplusplus.com/doc/tutorial/other_data_types/
int test_typedef_2()
{// In C++, there are two syntaxes for creating such type aliases:// The first, inherited from the C language, uses the typedef keyword:// typedef existing_type new_type_name;
{ typedef char C;typedef unsigned int WORD;typedef char * pChar;typedef char field [50];C mychar, anotherchar, *ptc1;WORD myword;pChar ptc2;field name;
}// a second syntax to define type aliases was introduced in the C++ language:// using new_type_name = existing_type;
{//the same type aliases as above could be defined as:using C = char;using WORD = unsigned int;using pChar = char *;using field = char [50];
}{// 注意: typedef int* INT; const INT p;相當(dāng)于int* const p;而不是const int* p;typedef int* INT;int a[] = {1, 2, 3};const INT p1 = &a[0];const int* p2 = &a[0];//++p1; // error: increment of read-only variable 'p1'p1[0] = -100;fprintf(stdout, "a[0]: %d\n", a[0]);++p2;//p2[0] = -200; // error: assignment of read-only location '*p2'
}return 0;
}// reference: https://msdn.microsoft.com/en-us/library/dn467695.aspx
void actual_function(int arg) { fprintf(stdout, "value: %d\n", arg); }
template<typename T>
using ptr2 = T*;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 {fprintf(stdout, "start allocate\n");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 {fprintf(stdout, "start deallocate\n");free(p);}
};using MyIntVector = std::vector<int, MyAlloc<int>>;int test_typedef_3()
{{ // An alias does not introduce a new type and cannot change the meaning of an existing type name// C++11 using counter = long; // C++03 equivalent: // typedef long counter;
}{ // Aliases also work with function pointers// C++11 using func = void(*)(int); // C++03 equivalent: // typedef void (*func)(int); // func can be assigned to a function pointer value func fptr = &actual_function;fptr(10);
}{ // 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*; // error: a template declaration cannot appear at block scope // the name 'ptr<T>' is now an alias for pointer to T ptr2<int> ptr_int;
}{ // an alias template with a custom allocatorMyIntVector foov = { 1701, 1764, 1664 };for (auto a: foov)fprintf(stdout, " %d ", a);fprintf(stdout, "\n");
}return 0;
}///
// reference: https://zh.wikipedia.org/zh-hk/Typedef
int do_math(float arg1, int arg2) { return arg2; }int call_a_func(int (*call_this)(float, int))
{int output = call_this(5.5, 7);return output;
}// 將上面改為使用typedef,回調(diào)函數(shù)
typedef int (*MathFunc)(float, int);
int call_a_func2(MathFunc call_this)
{int output = call_this(5.5, 7);return output;
}int test_typedef_4()
{int final_result = call_a_func(&do_math);fprintf(stdout, "final_result: %d\n", final_result);int final_result2 = call_a_func2(&do_math);fprintf(stdout, "final_result2: %d\n", final_result2);return 0;
}// reference: https://en.cppreference.com/w/cpp/language/type_alias
// type alias, identical to
// typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
// the name 'flags' now denotes a type:
flags fl = std::ios_base::dec;// type alias, identical to
// typedef void (*func)(int, int);
using func = void (*) (int, int);
// the name 'func' now denotes a pointer to function:
void example(int, int) {}
func f = example;// alias template
template<class T>
using ptr = T*;
// the name 'ptr<T>' is now an alias for pointer to T
ptr<int> x;// type alias used to hide a template parameter
template<class CharT>
using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
mystring<char> str;// type alias can introduce a member typedef name
template<typename T>
struct Container { using value_type = T; };
// which can be used in generic programming
template<typename Container>
void g(const Container& c)
{typename Container::value_type n;fprintf(stdout, "type: %s\n", typeid(n).name());
}// type alias used to simplify the syntax of std::enable_if
template<typename T>
using Invoke = typename T::type;
template<typename Condition>
using EnableIf = Invoke<std::enable_if<Condition::value>>;
template<typename T, typename = EnableIf<std::is_polymorphic<T>>>
int fpoly_only(T t) { return 1; }struct S { virtual ~S() {} };int test_typedef_5()
{Container<int> c;g(c); // Container::value_type will be int in this function//fpoly_only(c); // error: enable_if prohibits thisS s;fpoly_only(s); // okay: enable_if allows thisreturn 0;
}} // namespace typedef_
CMakeLists.txt內(nèi)容如下:
PROJECT(CppBaseTest)
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)# 支持C++11
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -O2 -std=c11")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2 -std=c++11")
# 支持C++14, when gcc version > 5.1, use -std=c++14 instead of c++1y
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -O2 -std=c++1y")MESSAGE(STATUS "project source dir: ${PROJECT_SOURCE_DIR}")
SET(PATH_SRC_FILES ${PROJECT_SOURCE_DIR}/./../../demo/CppBaseTest)
MESSAGE(STATUS "path src files: ${PATH_SRC_FILES}")# 指定頭文件的搜索路徑
INCLUDE_DIRECTORIES(${PATH_SRC_FILES})# 遞歸查詢所有匹配的文件:*.cpp
FILE(GLOB_RECURSE CPP_LIST ${PATH_SRC_FILES}/*.cpp)
FILE(GLOB_RECURSE C_LIST ${PATH_SRC_FILES}/*.c)
#MESSAGE(STATUS "cpp list: ${C_LIST}")# 編譯可執(zhí)行程序
ADD_EXECUTABLE(CppBaseTest ${CPP_LIST} ${C_LIST})
# 用來(lái)為target添加需要鏈接的共享庫(kù),指定工程所用的依賴庫(kù),包括動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)
TARGET_LINK_LIBRARIES(CppBaseTest pthread)
build.sh腳本內(nèi)容如下:
#! /bin/bashreal_path=$(realpath $0)
dir_name=`dirname "${real_path}"`
echo "real_path: ${real_path}, dir_name: ${dir_name}"new_dir_name=${dir_name}/build
mkdir -p ${new_dir_name}
cd ${new_dir_name}
cmake ..
makecd -
編譯及測(cè)試方法如下:首先執(zhí)行build.sh,然后再執(zhí)行./build/CppBaseTest即可。
GitHub: https://github.com/fengbingchun/Messy_Test??
總結(jié)
以上是生活随笔為你收集整理的C++/C++11中用于定义类型别名的两种方法:typedef和using的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C++中标准模板库std::vector
- 下一篇: C++中的内存对齐介绍