0

考虑一种情况,您的任务是为标准库容器编写一个简单的漂亮打印工具。在标题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.hppprint_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作为示例(我确信有很多更好的方法可以漂亮地打印容器),但您可能还有其他原因想要这样做(例如,在include之前在其中创建lean_windows.h标题“包装器” )。#define WIN32_LEAN_AND_MEANwindows.h

我看不出这种方法有什么问题,因为这意味着您避免了在编译单元中引入一堆您可能不需要/不需要的头文件而导致的潜在膨胀。尽管如此,它仍然感觉“错误”,因为其他人可能看不到您的“包含包装器”实际上包含您想要的标头,并且似乎玷污了包含标准库标头的“神圣性”(#include <string>是惯用的,而#include "string_wrapper.hpp"不是)。

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

4

3 回答 3

1

一些图书馆处理这类事情的一种方式是让用户决定。制作类似print/vector.hppand的文件print/set.hpp,也制作一个类似的文件print/all.hpp(或者只是print.hpp,尽管这可能会鼓励坏习惯)。最后一个文件只是#includes所有单独的文件,所以想要“方便”的人可以拥有它,而那些想要精简和平均编译的人也可以拥有它。

与上述类似的一个常见示例是 Boost 的智能指针库: http: //www.boost.org/doc/libs/release/boost/smart_ptr.hpp

于 2013-02-13T12:03:16.873 回答
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);
}

现在,这些函数得到保护,不会被其他函数弄错,并且您的代码保持安全和优雅。

我看到的唯一缺点是,包含长标头会使编译过程更长一些。但是,我认为,我们最多只讨论十分之一秒,所以如果你不是在处理像 old 386 这样的东西,那应该不是一个大问题(更不用说预编译的头文件,但老实说我做到了一次也没用过)。

于 2013-02-13T12:05:17.317 回答
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
   }
}
于 2013-02-13T12:35:21.013 回答