条款九 倾向使用别名声明而非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&lt;T>的时候,它知道MyAllocList<T>是一种类型,因为MyAllocList是别名模板:它必须命名一种类型。因此MyAllocList<T>是一种独立类型,typename既不需要又不允许。

当编译器遇到使用MyAllocList&lt;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的类型转换特性提供了别名模板


Azathoth
26 声望1 粉丝