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_printlean_windows.h#define WIN32_LEAN_AND_MEANwindows.h

コンパイル単位で使用しない/必要としない可能性のある一連のヘッダーを導入する可能性のある肥大化を回避していることを意味するため、このアプローチに問題はありません。それにもかかわらず、「インクルードラッパー」が実際に意図したヘッダーをインクルードし、標準ライブラリヘッダーをインクルードする「神聖さ」を損なうように思われるという意味で、他の人には明らかではないという意味で「間違っている」と感じています (#include <string>は慣用的ですが、#include "string_wrapper.hpp"ではありません)。

これは悪い習慣と見なされますか\悪い設計を示していますか?

4

3 に答える 3

1

一部のライブラリがこの種のことを処理する 1 つの方法は、ユーザーに決定させることです。ファイルを と のようprint/vector.hppに作成しprint/set.hpp、ファイルも のようにしますprint/all.hpp(または単にprint.hpp、悪い習慣を助長する可能性があります)。その最後のファイルには、個々のファイルがすべて #include されているだけなので、「便利さ」を望む人はそ​​れを使用でき、無駄のないコンパイルを望む人もそれを使用できます。

上記と同様に動作する一般的な例は、Boost のスマート ポインター ライブラリです: http://www.boost.org/doc/libs/release/boost/smart_ptr.hpp

于 2013-02-13T12:03:16.873 に答える
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 に答える
0

本当に必要なのか、お聞きしたいです。あなたはゆっくりと 1 クラス 1 ヘッダーの方向に引き寄せられ、#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 のようなものに取り組んでいないのであれば、大きな問題にはならないはずです (プリコンパイル済みヘッダーは言うまでもありませんが、正直なところ、一度も使用していません)。

于 2013-02-13T12:05:17.317 に答える