我发现自己编写了很多类型别名(typedef)来使代码更容易更改,但同时有些东西告诉我要避免这样做,因为它会给那些打算使用它的人带来很多困惑。 /在我的代码上。
也许不是最好的例子,但看看here。我还会举一个最近的例子;这些是我在构建XML解析器时弄乱的一些类:
namespace XML
{
struct Attribute
{
typedef std::string name_t;
typedef std::string value_t;
Attribute(const name_t &name, const value_t &value = "");
name_t name;
value_t value;
};
}
namespace XML
{
class Element
{
private:
typedef std::list<Attribute> attribute_container;
typedef std::list<Element> element_container;
public:
typedef attribute_container::iterator attribute_iterator;
typedef attribute_container::const_iterator const_attribute_iterator;
typedef element_container::iterator element_iterator;
typedef element_container::const_iterator const_element_iterator;
typedef std::string name_t;
typedef std::string data_t;
...
private:
name_t _name;
data_t _data;
attribute_container _attributes;
element_container _child_elements;
以这种方式做事会使编写代码变得更容易,也许它会让它更直观但是这种做法的缺点是什么?
答案 0 :(得分:5)
这是我的5美分。你只需要在某些情况下制作那些typedef。例如,如果您正在编写自己的迭代器类,则必须使其与iterator_traits
一起使用并提供嵌套的typedef,如difference_type
等。在某些情况下,容器也适用。例如,如果某些常用函数是这样写的:
template <typename T>
void foo(T::iterator it);
然后无论T
被指定为模板参数,它都必须声明嵌套的iterator
类型。您可以引入自己的额外模板接口约定,并在整个代码中遵循它们。
嵌套类型有用的另一种情况是别名模板参数,让代码的其他部分引用它。例如:
template <typename T>
class Foo {
public:
typedef T now_you_can_access_this_from_the_outside;
};
但除此之外 - 不需要typedefing。然后这是一个偏好的问题,但我打赌我的房子 - std::string
比value_t
更具可读性,因为每个人都知道std::string
是什么,value_t
什么都不告诉关于自己。
答案 1 :(得分:2)
我的经验法则是,如果使用的typedef超过2-3次,则值得存在。 否则,这是墨水的浪费,这对环境不利。
答案 2 :(得分:1)
主观上,当正确完成时,这实际上使代码更容易阅读和理解。同样在std
和扩展名boost
中广泛使用,因此您可能只想保持一致。
答案 3 :(得分:1)
有效的编程是关于你可以适应的东西。如果定义一种类型可以更容易地适应你的头脑,那就去做吧。但如果你做得太多,跟踪太多类型的认知负担会对你造成伤害。
例如,我可能会使用一个:
typedef std::map<std::string, std::vector<std::string> > SynonymMap;
总结一下,你将为程序中的每个变量创建一个新类型。这有多可读?