条款九 倾向使用别名声明而非typedef
简介
在C++98
中可以使用typedef
简化定义:
typedef std::unique_ptr<std::unordered_map<std::string, std::string>> UPtrMapSS;
在C++11
中提供了别名声明(alias declarations)的方式:
using UPtrMapSS = std::unique_ptr<std::unordered_map<std::string, std::string>>;
这两种方式实现了相同的功能,但是在处理函数指针
的时候后者更容易被理解。
typedef void(*FP)(int, const std::string&); // typedef
using FP = void(*)(int, const std::string&); // alias declaration
倾向使用别说声明的强烈原因是,别名声明可以模板化,而typedef不行
案例
以下例子定义一个使用自定义分配器MyAlloc的链表的同义词:
// alias declaration
template<typename T>
using MyAllocList = std::List<T, MyAlloc<T>>;
MyAllocList<Widget> lw;
// typedef
template<typename T>
struct MyAllocList{
typedef std::List<T, MyAlloc<T>> type;
};
MyAllocList<Widget>::type lw;
若要在一个模板内定义一个链表:
// typedef
template<typename T>
class Widget {
typename MyAllocList<T>::type list;
};
// alias declaration
template<typename T>
class Widget {
MyAllocList<T> list;
};
当编译器遇到使用MyAllocList<T>
的时候,它知道MyAllocList<T>是一种类型,因为MyAllocList是别名模板:它必须命名一种类型。因此MyAllocList<T>是一种独立
类型,typename
既不需要又不允许。
当编译器遇到使用MyAllocList<T>::type
的时候,它不能确定这是一种类型,因为可能存在一种MyAllocList的特化(specialization),MyAllocList<T>::type不表示为类型,例如:
class Wine{};
template<>
class MyAllocList<Wine> {
enum class WineType{
White, Red, Rose
};
WineType type; // type is a data member
}
高级
在进行模板元编程(TMP)的时候,往往需要类型转换。C++11
在<type_traits>
头文件中一共了一些方法,把类型T
转换为std::transformation<T>::type
类型。
// C++11, use typedef
std::remove_const<T>::type // const T -> T
std::remove_reference<T>::type // T&(T&&) -> T
std::add_lvalue_reference<T>::type // T -> T&
// C++14, use alias declaration
std::remove_const_t<T>
std::remove_reference_t<T>
std::add_lvalue_reference_t<T>
总结
typedef不支持模板化,但是别名声明支持
别名模板避免了“::type”后缀,并且在模板中,使用typedef是需要的前缀“typename”可以舍去
C++14为C++11的类型转换特性提供了别名模板