考虑一种情况,您的任务是为标准库容器编写一个简单的漂亮打印工具。在标题pretty_print.hpp
中,您声明了以下函数:
// In pretty_print.hpp
template<typename T>
void pretty_print(std::ostream& os, std::vector<T> const& vec);
template<typename T>
void pretty_print(std::ostream& os, std::set<T> const& set);
template<typename T, typename U>
void pretty_print(std::ostream& os, std::map<T, U> const& map);
// etc.
但是,由于无法向前声明容器,因此每个容器标头必须#include
。因此,将pretty_print.hpp
包含到库的其他部分(可能?)会导致相当多的代码膨胀。因此,为了避免将这些依赖项引入其他编译单元,您需要创建一组文件(我称之为“标题包装器”,因为我找不到任何其他术语),称为print_vector.hpp
,{{ 1}}等等都有类似的布局:
print_set.hpp
因此,当您希望能够// In print_vector.hpp
#include <vector>
template<typename T>
void pretty_print(std::ostream& os, std::vector<T> const& vec);
// In print_set.hpp
#include <set>
template<typename T>
void pretty_print(std::ostream& os, std::set<T> const& set);
// you get the point
向量时,您pretty_print
并且它只会将#include print_vector.hpp
引入当前编译单元而不是<vector>
, <set>
或您可能不需要的任何其他标题。请注意,我使用<map>
作为示例(我确信有很好的方法可以打印容器)但是还有其他原因可能需要这样做(例如制作pretty_print
在包含lean_windows.h
)之前#define WIN32_LEAN_AND_MEAN
的标题'封面'。
我看不出这种方法有什么问题,因为这意味着你要避免引入一堆你可能在编译单元中不需要/不需要的标题。尽管如此,它仍然感觉“错误”,因为对于其他人来说可能并不明显,“包装包装”实际上包含了您想要的标题,并且似乎玷污了包含标准库标题的“神圣性”({{1}是惯用的,而windows.h
不是。)
这被认为是不好的做法\表明设计不好吗?
答案 0 :(得分:1)
一些图书馆处理此类事情的一种方法是让用户决定。制作print/vector.hpp
和print/set.hpp
等文件,并制作print/all.hpp
(或仅print.hpp
之类的文件,但这可能会鼓励不良习惯)。最后一个文件只是#includes所有个人,所以想要“方便”的人可以拥有它,那些想要精益求精的人也可以拥有它。
与上述类似的常见示例是Boost的智能指针库:http://www.boost.org/doc/libs/release/boost/smart_ptr.hpp
答案 1 :(得分:0)
我宁愿问,是否真的有必要。你慢慢倾向于一流的一个方向,这将把你的#include部分变成一个痛苦的混乱。
如果你想确定,你不会将标识符误认为是另一个,只需使用命名空间。
namespace PrettyPrint
{
template<typename T>
void pretty_print(std::ostream& os, std::vector<T> const& vec);
template<typename T>
void pretty_print(std::ostream& os, std::set<T> const& set);
template<typename T, typename U>
void pretty_print(std::ostream& os, std::map<T, U> const& map);
}
现在,这些功能可以防止被别人误解,您的代码仍然安全而优雅。
我看到的唯一缺点是,包括长标题会使编译过程更长一些。但是,我认为,我们最多谈论的是十分之几秒,所以如果你没有像旧的386这样的东西,这不应该是一个大问题(更不用说预编译的标题,但说实话,我做了甚至没有使用过它们。)
答案 2 :(得分:0)
您可以尝试更通用的版本:
template<class T>
void print_element(std::ostream& os, T const& element)
{
os << T;
}
template<class Key,class Value>
void print_element(std::ostream& os, std::pair<Key,Value> const& element)
{
os << '(' << element->first << ',' << element->second << ')';
}
template<typename Container>
void pretty_print(std::ostream& os, Container const& c)
{
for (auto i: c)
{
// print some stuff
print_element(os, *i);
// print other stuff
}
}