次のようなテンプレート関数を記述する場合:
template<class T> void print(T const & collection)
コレクションをループしてイテレータを逆参照するとき、vector<int>
に変更しない限り、次のようなものがあればすべて正常に機能しますvector<int*>
。コードを複製せずに、単一のテンプレート関数の違いに対処する最善の方法は何ですか?
次のようなテンプレート関数を記述する場合:
template<class T> void print(T const & collection)
コレクションをループしてイテレータを逆参照するとき、vector<int>
に変更しない限り、次のようなものがあればすべて正常に機能しますvector<int*>
。コードを複製せずに、単一のテンプレート関数の違いに対処する最善の方法は何ですか?
do_print
クラス template に委譲する単一のテンプレート関数を作成しprinter
ます。クラス テンプレートは、プリティ プリントを行う関数オブジェクトであり、 でT*
プリティ プリント バージョンを呼び出すだけで部分的に特殊化できます*t
。
そのため、プリティ プリンティング コードの重複はなく、2 つの軽量実装クラスを作成する際の多少の不都合はありません (これらは最新のコンパイラによって最適化されるため、実行時のオーバーヘッドはありません)。
私は、SFINAE トリックよりもこのソリューションを好みます。なぜなら、部分的なクラスの特殊化は、関数オーバーロードのトリックよりもはるかに多くの制御 (およびより適切なエラー メッセージ) を提供するからです。Alexandrescu & Sutter Coding Standards でも推奨されています。
ところで、このコードは にも機能T**
しT*
ますT
。sendも同様で、最終的に にT**
送信されます。実際、任意のレベルの間接化は、ポインターが指す要素を出力することになります。T*
T
#include <iostream>
#include <vector>
namespace detail {
template<typename T>
struct printer
{
void operator()(T const& t)
{
std::cout << t; // your pretty print code here
}
};
template<typename T>
struct printer<T*>
{
void operator()(T const* t)
{
printer<T>()(*t); // delegate to printing elements (no duplication of prettty print)
}
};
}
template<typename T>
void do_print(T const& t)
{
detail::printer<T>()(t);
}
template<typename C>
void print(C const& collection)
{
for(auto&& c: collection)
do_print(c);
std::cout << "\n";
}
int main()
{
int a = 1;
int b = 2;
auto c = &a;
auto d = &b;
std::vector<int> v1 { a, b };
std::vector<int*> v2 { c, d };
std::vector<int**> v3 { &c, &d };
print(v1);
print(v2);
print(v3);
}
ライブワークスペースへの出力