在我从事C ++(MFC)编程的那几年中,我从没有感觉到需要使用typedef
,因此我真的不知道它的用途。我应该在哪里使用?在某些实际情况下,typedef
首选使用吗?还是这真的是特定于C的关键字?
Answers:
typedef
对于许多模板元编程任务来说是必需的-每当将一个类视为“编译时类型函数”时,就将a用作“编译时类型值”以获取结果类型。例如,考虑将指针类型转换为其基本类型的简单元函数:typedef
template<typename T>
struct strip_pointer_from;
template<typename T>
struct strip_pointer_from<T*> { // Partial specialisation for pointer types
typedef T type;
};
示例:类型表达式的strip_pointer_from<double*>::type
计算结果为double
。注意,模板元编程在库开发之外并不常用。
typedef
是有帮助的用于给出一个短,锋利的别名复杂函数指针类型:
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;
并且您的程序仍将在新的实现上运行。
与函数指针一起使用
使用typedef隐藏函数指针声明
void (*p[10]) (void (*)() );
只有很少的程序员可以说p是“由10个指向返回void的函数的指针组成的数组,并采用指向另一个返回void并且不带参数的函数的指针组成的数组”。繁琐的语法几乎难以理解。但是,您可以使用typedef声明将其大大简化。首先,为“指向返回空值且不带参数的函数的指针”声明一个typedef,如下所示:
typedef void (*pfv)();
接下来,根据先前声明的typedef声明另一个typedef,以表示“指向返回空值并获取pfv的函数的指针”:
typedef void (*pf_taking_pfv) (pfv);
现在,我们已经创建了pf_taking_pfv typedef作为笨拙的“指向返回void并获取pfv的函数的指针”的同义词,声明一个由10个这样的指针组成的数组很容易:
pf_taking_pfv p[10];
只是为了提供一些例子说明事情:STL容器。
typedef std::map<int,Froboz> tFrobozMap;
tFrobozMap frobozzes;
...
for(tFrobozMap::iterator it=frobozzes.begin(); it!=map.end(); ++it)
{
...
}
甚至使用像
typedef tFrobozMap::iterator tFrobozMapIter;
typedef tFrobozMap::const_iterator tFrobozMapCIter;
另一个例子:使用共享指针:
class Froboz;
typedef boost::shared_ptr<Froboz> FrobozPtr;
[更新]根据评论-放在哪里?
最后一个示例-使用shared_ptr
-很简单:是真正的标头材料-或至少是正向标头。无论如何,您确实需要shared_ptr的正向声明,并且其声明的优点之一是可以安全地与正向decl一起使用。
换句话说,如果存在shared_ptr,则可能应该仅通过shared_ptr使用该类型,因此分隔声明没有多大意义。
(是的,xyzfwd.h很痛苦。我只会在热点中使用它们-知道热点很难识别。怪罪于C ++编译+链接模型...)
容器typedef我通常在声明容器变量的地方使用-例如,当实际容器实例是类成员时,在本地var中作为类成员。如果实际容器类型是实现详细信息,则此方法效果很好-不会引起任何其他依赖关系。
如果它们成为特定接口的一部分,则将它们与使用的接口一起声明,例如
// FrobozMangler.h
#include "Froboz.h"
typedef std::map<int, Froboz> tFrobozMap;
void Mangle(tFrobozMap const & frobozzes);
当类型是不同接口之间的绑定元素时,即成为问题,即多个报头需要相同的类型。一些解决方案:
我同意后两者并不是那么好,我只会在遇到麻烦时才使用它们(不是主动地)。
typedef在许多情况下很有用。
基本上,它允许您为类型创建别名。当/如果您必须更改类型,则其余代码可能保持不变(当然,这取决于代码)。例如,假设您要遍历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的一个好理由是某些东西的类型可能会改变。例如,假设现在,16位int可以很好地为某些数据集建立索引,因为在可预见的将来,您将拥有少于65535个项目,并且空间限制很大,或者您需要良好的缓存性能。但是,如果您需要在包含超过65535个项目的数据集上使用程序,那么希望能够轻松切换到更大的整数。使用typedef,您只需在一个地方进行更改。
使用typedef的另一个用例是当我们要启用一种 容器独立代码(但不完全是!)时。
让我们说您上课了:
Class CustomerList{
public:
//some function
private:
typedef list<Customer> CustomerContainer;
typedef CustomerContainer::iterator Cciterator;
};
上面的代码使用typedef封装了内部容器的实现,即使将来需要将列表容器更改为vector或双端队列,CustomerList类的用户也不必担心确切的容器实现。
因此,typedef封装并在某种程度上帮助我们编写了独立于容器的代码
...并且您不需要枚举或结构的Typedef。
还是你
typedef enum { c1, c2 } tMyEnum;
typedef struct { int i; double d; } tMyStruct;
可以更好地写成
enum tMyEnum { c1, c2 }
struct tMyStruct { int i; double d; };
那是对的吗?C呢?