使用'include wrapper'是否被认为是不良做法/表示设计不佳?
Is using an 'include wrapper' considered bad practice/indicative of bad design?
考虑这样一种情况:您的任务是为标准库容器编写一个简单漂亮的打印工具。在标题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
、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
作为示例(我相信有比漂亮的打印容器优越得多的方法),但您可能还想这样做还有其他原因(例如,在包含windows.h
之前,在#define WIN32_LEAN_AND_MEAN
的位置制作lean_windows.h
标头"包装器")。
我看不出这种方法有什么错,因为它意味着你可以避免在编译单元中引入一堆你可能不使用/不需要的头导致的潜在膨胀。尽管如此,它仍然感觉"错误",因为对其他人来说,你的"包含包装器"实际上包含了你想要的头,并且似乎玷污了包含标准库头的"神圣性"(#include <string>
是惯用的,而#include "string_wrapper.hpp"
不是)。
这种做法是否被认为是不良设计的表现?
一些库处理这类事情的一种方法是让用户决定。制作print/vector.hpp
和print/set.hpp
这样的文件,也制作print/all.hpp
这样的文件(或者只是print.hpp
,尽管这可能会助长坏习惯)。最后一个文件只是#包括了所有单独的文件,所以想要"方便"的人可以拥有它,而那些想要精简编译的人也可以拥有它。
Boost的智能指针库是一个与上面类似的常见示例:http://www.boost.org/doc/libs/release/boost/smart_ptr.hpp
我宁愿问,这是否真的有必要。你慢慢地被吸引到一类一头的方向,这会把你的#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这样的东西,那应该不是什么大问题(更不用说预编译的头了,但老实说,我甚至一次也没有使用过它们)。
您可以简单地尝试一个更通用的版本:
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
}
}
- 表示"accepting anything for this template argument" C++概念的通配符
- 如何将ampl中的集合表示为c++中的向量
- std::is_base_of表示ctor编译错误
- 输入中的字符串数未知(以字母表示)
- 我可以信任表示整数的浮点或双精度来保持精度吗
- c++模板来表示多项式
- 询问在设计我的手臂模拟器功能表示格式1
- CMakeLists.txt中的命名空间表示法
- C++射线示踪剂ppm表示没有足够的数据来显示图像
- 如何计算Big-O表示法中的平均渐近运行时间
- 我应该如何表示我拥有的连续元素序列?
- 在C++中,使用带有 std::optional 参数的函数<T>来表示可选参数是否有意义?
- 在 std::无符号字符的向量处存储 int 的十六进制表示形式
- 表示类模板C++空类型
- 具有所表示类的相同构造函数签名的代理类模板
- 嵌套在循环中的两个循环的 big-O 表示法
- 具有引用成员的结构是否具有唯一的对象表示形式
- 使用 int 表示浮点除法 C++
- 安装可可荚后,现有的静态库不使用libssl.A表示TLS连接和访问不良
- 使用'include wrapper'是否被认为是不良做法/表示设计不佳?