1

同様のタイプのコンテンツを印刷するためのジェネリック関数を定義したいと思いstd::mapます。私の最初の試みは次のような関数です:

template <class K, class V>
inline void PrintCollection(const std::map<K,V>& map,
                            const char* separator="\n",
                            const char* arrow="->",
                            const char* optcstr="") {
  typedef typename std::map<K,V>::const_iterator iter_type;
  std::cout << optcstr;
  for (iter_type begin = map.begin(), it = begin, end = map.end();
       it != end; ++it) {
    if (it != begin) {
      std::cout << separator;
    }
    std::cout << it->first << arrow << it->second;
  }
  std::cout << std::endl;
}

これは正常に動作します。この関数をもう1つのステップで一般化しようとすると、つまりstd::multimap型に対して機能するようにすると、コンパイラーは怒ります。std::map関数定義でジェネリックにするいくつかの方法を試しました。たとえば、次のようになります。

template <class M, class K, class V>
inline void PrintCollection(const M<K,V>& map,
                            const char* separator="\n",
                            const char* arrow="->",
                            const char* optcstr="") {
  typedef typename M<K,V>::const_iterator iter_type;
  std::cout << optcstr;
  for (iter_type begin = map.begin(), it = begin, end = map.end();
       it != end; ++it) {
    if (it != begin) {
      std::cout << separator;
    }
    std::cout << it->first << arrow << it->second;
  }
  std::cout << std::endl;
}

成功しませんでした。

上で定義したように、この関数を一般化するにはどうすればよいですか?

より明確にするために、私はすでにこの関数の前に定義されたベクトルのようなクラスに対して定義された関数を持っています。のような

template <class T>
inline void PrintCollection(const T& collection,
                            const char* separator="\n",
                            const char* optcstr="") {
  typedef typename T::const_iterator iter_type;

  std::cout << optcstr;

  for (iter_type begin = collection.begin(), it = begin, end = collection.end();
       it != end;
       ++it) {
    if (it != begin) {
      std::cout << separator;
    }
    std::cout << *it;
  }

  std::cout << std::endl;
}

それで、この関数をマップのようなクラスに特化させるためにそれを達成したいと思います。私はC++にかなり慣れていないので、この種のものの正確な用語はわかりません。これは「テンプレートの特殊化」と呼ばれますか?

4

3 に答える 3

4

stdlibと同じように実行し、アルゴリズムインターフェイスでイテレータを使用します。これは最も一般的なソリューションです。

template<class Iter>
void PrintCollection(Iter first, Iter last,
                     const char* separator="\n",
                     const char* arrow="->",
                     const char* optcstr="") 
{
    typedef Iter iter_type;
    std::cout << optcstr;
    for (iter_type begin = first, it = begin, end = last;
        it != end; ++it) {
    if (it != begin) {
        std::cout << separator;
    }
    std::cout << it->first << arrow << it->second;
    }
    std::cout << std::endl;
}


int main()
{
    vector<pair<int, int>> collection;
    map<int, int> collection2;
    pair<int, int> collection3[3];

    PrintCollection(begin(collection), end(collection));
    PrintCollection(begin(collection2), end(collection2));
    PrintCollection(begin(collection3), end(collection3));
}
于 2012-06-25T06:37:27.177 に答える
2

答えはかなり簡単です。

Kタイプ名やV関数に依存することはありません。したがって、それらを削除して、一般的なテンプレートを作成します。mapとの両方に使用できますmultimap

template <class AnyMap>
void PrintCollection(const AnyMap& map,
  ...
{
  typedef typename AnyMap::const_iterator iter_type;

ちなみに、 sを使用すると、キーワードtemplateは必要ありません。inline

于 2012-06-25T06:46:53.310 に答える
1

template-templateパラメーターを使用できます

template<template<class, class> class M, class K, class V>
inline void PrintCollection(const M<K, V>& map, /* rest as before */)
{
    // rest as before
}

int main()
{
    std::map<int, int> m1;
    std::multi_map<int, int> m2;

    // fill both maps

    PrintCollection(m1);
    PrintCollection(m2);
}

しかし、hansmaadが指摘しているように、パラメーターとしてコンテナーの代わりにイテレーターのペアを使用することもできます。一般に、非常に一般的で、型があり、型PrintCollectionがあるという事実を利用しない場合は、そのソリューションをお勧めします。OTOH、将来のバージョンでもその情報を印刷する必要がある場合は、これら2つのタイプをパラメーターとして受け取るtemplate-templateパラメーターを使用することをお勧めします。KeyValuePrintCollection

于 2012-06-25T06:38:02.533 に答える