是否使用'包装纸'被视为不良做法/表明设计不良?

时间:2013-02-13 11:59:51

标签: c++ include

考虑一种情况,您的任务是为标准库容器编写一个简单的漂亮打印工具。在标题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不是。)

这被认为是不好的做法\表明设计不好吗?

3 个答案:

答案 0 :(得分:1)

一些图书馆处理此类事情的一种方法是让用户决定。制作print/vector.hppprint/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
   }
}