什么时候应该在C ++中使用typedef?

在我多年的C ++(MFC)编程中,我从来没有觉得需要使用typedef ,所以我真的不知道它用的是什么。 我应该在哪里使用它? 有没有使用typedef实际情况? 或者这真的是一个特定于C的关键字?

模板元编程

typedef对于许多模板元编程任务是必需的 – 无论何时将类视为“编译时types函数”, typedef将用作“编译时types值”来获取结果types。 例如考虑一个简单的元函数来将指针types转换为其基types:

 template<typename T> struct strip_pointer_from; template<typename T> struct strip_pointer_from<T*> { // Partial specialisation for pointer types typedef T type; }; 

示例:typesexpression式strip_pointer_from<double*>::type计算结果为double 。 请注意,模板元编程不是在图书馆开发之外常用的。

简化函数指针types

typedef 有助于为复杂的函数指针types提供一个简短的尖锐别名:

 typedef int (*my_callback_function_type)(int, double, std::string); void RegisterCallback(my_callback_function_type fn) { ... } 

在Bjarne的书中,他表示可以使用typedef来处理具有不同整数大小的系统之间的可移植性问题。 (这是一个释义)

在sizeof(int)是4的机器上,你可以

 typedef int int32; 

然后在你的代码中使用int32。 当你移动到sizeof(int)为2的C ++实现时,你可以改变typdef

 typedef long int32; 

而且你的程序仍然在新的实现上工作。

只是提供一些事情说的东西:STL容器。

  typedef std::map<int,Froboz> tFrobozMap; tFrobozMap frobozzes; ... for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it) { ... } 

甚至使用typedefs也不是不寻常的

 typedef tFrobozMap::iterator tFrobozMapIter; typedef tFrobozMap::const_iterator tFrobozMapCIter; 

再比如:使用共享指针:

 class Froboz; typedef boost::shared_ptr<Froboz> FrobozPtr; 

[更新]按照评论 – 把它们放在哪里?

最后一个例子 – 使用shared_ptr – 很简单:是真正的头文件 – 至less是一个前向头文件。 无论如何,您确实需要使用shared_ptr的前向声明,而其声明的优势之一是可以安全地使用forward decl。

换句话说:如果有一个shared_ptr,你可能只能通过shared_ptr来使用这个types,所以分离这些声明没有多大意义。

(是的,xyzfwd.h是一个痛苦的东西,我只能在热点地区使用它们 – 知道热点难以识别,指责C ++编译+链接模型…)

容器types定义我通常使用声明容器variables的地方 – 例如本地var作为类成员,当实际容器实例是类成员时。 如果实际的容器types是一个实现细节,这个效果很好 – 不会引起额外的依赖。

如果它们成为特定接口的一部分,那么它们将与它们所用的接口一起声明,例如

 // FrobozMangler.h #include "Froboz.h" typedef std::map<int, Froboz> tFrobozMap; void Mangle(tFrobozMap const & frobozzes); 

当types是不同接口之间的绑定元素时,这会产生问题 – 即多个头部需要相同的types。 一些解决scheme

  • 将其与所包含的types一起声明(适用于这种types的常用容器)
  • 将它们移动到一个单独的标题
  • 移动到一个单独的头部,并使其成为一个数据类,其中实际的容器再次是一个实现细节

我同意后者不是那么好,只有当我陷入困境(不主动)时才会使用它们。

与函数指针一起使用

使用typedef隐藏函数指针声明

 void (*p[10]) (void (*)() ); 

只有很less的程序员可以知道p是一个“返回一个返回void的函数的10个指针数组,并且指向另一个返回void且不带参数的函数的指针”。 繁琐的语法几乎难以辨认。 但是,通过使用typedef声明可以大大简化它。 首先,声明一个typedef为“指向返回void且不带参数的函数的指针”,如下所示:

  typedef void (*pfv)(); 

接下来,根据我们先前声明的typedef声明另一个typedef为“指向函数返回void和pfv”的指针:

  typedef void (*pf_taking_pfv) (pfv); 

现在我们已经创build了pf_taking_pfv typedef作为难以使用的“指向函数返回void和pfv的指针”的同义词,声明一个由10个这样的指针组成的数组很简单:

  pf_taking_pfv p[10]; 

typedef在很多情况下很有用。

基本上它允许你创build一个types的别名。 当/如果你必须改变types,其余的代码可以保持不变(这当然取决于代码)。 例如,让我们说你想在一个c + +向量

 vector<int> v; ... for(vector<int>::const_iterator i = v->begin(); i != v.end(); i++) { // Stuff here } 

将来你可能会想用列表来改变向量,因为你必须对它进行一些操作。 没有typedef,你必须在你的代码中改变所有的vector。 但是,如果你写这样的东西:

 typedef vector<int> my_vect; my_vect v; ... for(my_vect::const_iterator i = v->begin(); i != v.end(); i++) { // Stuff here } 

现在你只需要改变一行代码(即从“ typedef vector<int> my_vect ”改为“ typedef list<int> my_vect ”),一切正常。

当你有复杂的数据结构时,typedef也可以节省你的时间,这些数据结构非常长(而且很难读)

使用typedef的一个很好的理由是如果东西的types可能改变。 例如,假设现在16位整数对索引某个数据集是很好的,因为在可预见的未来,您将只有不到65535个项目,并且空间限制很大,或者您需要良好的caching性能。 但是,如果您需要在超过65535个项目的数据集上使用您的程序,则希望能够轻松切换到更宽的整数。 使用typedef,你只需要在一个地方改变它。

typedef允许不仅为复杂types设置别名,还为您提供一个自然的文档types。 我有时会将其用于文档目的。

有些时候我使用一个字节数组。 现在,一个字节数组可能意味着很多事情。 typedef可以方便地将我的字节数组定义为“hash32”或“fileContent”,使我的代码更具可读性。

typedef的实际使用:

  • 为冗长的模板types提供友好的别名
  • 为函数指针types提供友好的别名
  • 为types提供本地标签,例如:

     template<class _T> class A { typedef _T T; }; template<class _T> class B { void doStuff( _T::T _value ); }; 

还有另外一个用例使用typedef是我们想要启用一种容器独立代码 (但不完全是!)

让我们说你有课:

 Class CustomerList{ public: //some function private: typedef list<Customer> CustomerContainer; typedef CustomerContainer::iterator Cciterator; }; 

上面的代码使用typedef封装了内部容器实现,即使未来列表容器需要更改为vector或deque,CustomerList类的用户也不需要担心确切的容器实现。

因此,typedef封装并有点帮助我们编写Container Independent代码

每当它使源更清晰或更好地阅读。

在C#中使用generics/模板的typedef。 “NodeMapping”只是更好地阅读/使用和理解了很多“Dictionary <string,XmlNode>”。 恕我直言。 所以我会推荐它的模板。

Typedef允许您的class级具有灵活性。 当你想改变程序中的数据types时,你不需要改变多个位置,只需要改变一次。

 typedef <datatype example int or double> value_type 

你可以给名字而不是value_type ,但是value_type通常是标准名字。

所以你可以使用typedef像

 value_type i=0; //same as a int or double i=0; 

…而你不需要一个枚举或结构的Typedef。

或者你呢?

 typedef enum { c1, c2 } tMyEnum; typedef struct { int i; double d; } tMyStruct; 

可以写得更好

 enum tMyEnum { c1, c2 } struct tMyStruct { int i; double d; }; 

那是对的吗? 那么C呢?