2

クラステンプレートがあります。const_iteratorこのクラス テンプレート内で、sのコレクションでsを受け入れるメンバー関数テンプレートを定義しようとしていますstring。コレクション自体は任意の種類の StdLib コレクションにすることができますが、現実的には か のいずれかになりvectorますlist

コレクションは任意の型になる可能性があるため、template-templateパラメーターを使用してコレクションの型を指定しています。ただし、常に のコレクションになりstringます。メンバー関数を呼び出すときにコレクションの型を指定する必要がないように、テンプレートの引数推定が機能するようにします。

私の意図したユースケースに似た SSCCE に続くコード。

これまでのところ、クラス定義 ( Live Demo ) は次のとおりです。

template <typename Foo>
struct Gizmo
{
    Foo mF;
    Gizmo (Foo f) : mF (f) {};

    template <template <typename> class Cont> void DoIt(
        typename Cont <string>::const_iterator begin,
        typename Cont <string>::const_iterator end)
        {
            stringstream ss;
            ss << "(" << this->mF << ")\n";
            const std::string s = ss.str();
            copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
        }
};

クラス テンプレートのインスタンス化のコンパイルが成功します。

int main()
{
    list <string> l;
    l.push_back ("Hello");
    l.push_back ("world");

    Gizmo <unsigned> g (42);
}

しかし、引数の演繹法を活用しようとすると (それがなければ、この演習全体はほとんど無意味です):

g.DoIt (l.begin(), l.end());

GCC は、テンプレート引数を推測できないと文句を言います。

prog.cpp: In function ‘int main()’:
prog.cpp:34:28: error: no matching function for call to ‘Gizmo<unsigned int>::DoIt(std::list<std::basic_string<char> >::iterator, std::list<std::basic_string<char> >::iterator)’
  g.DoIt (l.begin(), l.end());
                            ^
prog.cpp:34:28: note: candidate is:
prog.cpp:16:49: note: template<template<class> class typedef Cont Cont> void Gizmo<Foo>::DoIt(typename Cont<std::basic_string<char> >::const_iterator, typename Cont<std::basic_string<char> >::const_iterator) [with Cont = Cont; Foo = unsigned int]
  template <template <typename> class Cont> void DoIt(
                                                 ^
prog.cpp:16:49: note:   template argument deduction/substitution failed:
prog.cpp:34:28: note:   couldn't deduce template parameter ‘template<class> class typedef Cont Cont’
  g.DoIt (l.begin(), l.end());

最終的に、私が本当に気にかけているDoItのは、コレクションの begin および end イテレータで呼び出せることだけですstring。コレクションの実際のタイプはvectorまたはlistのいずれかであり、テンプレート引数を指定する必要も、コンテナーに基づいてオーバーロードする必要もありません。

どうすればこれを機能させることができますか?

私の実際のユースケースは C++03 であることに注意してください。C++11 ソリューションは歓迎されますが、C++03 ソリューションのみを受け入れることができます。

4

5 に答える 5

1

vector入力が、または 、listさらにはコンテナであるかどうかは、実際には気にしないことを提出します。あなたが実際に関心を持っているのは、変換可能なものを反復処理できる一連のものがあるということだけだと思いますstringvalue_type is_convertibleそのため、イテレータの任意のペアを受け入れる必要がありますstring( Coliru でのライブ デモ):

template <typename Iter>
typename enable_if<
  is_convertible<
    typename iterator_traits<Iter>::value_type,string
  >::value
>::type DoIt(Iter begin, Iter end) const
{
    stringstream ss;
    ss << "(" << this->mF << ")\n";
    const std::string s = ss.str();
    copy (begin, end, ostream_iterator <std::string> (cout, s.c_str()));
}

制約の見苦しさをお詫びします。Concepts Liteはすぐにここに到達できません。

于 2014-02-04T05:42:43.813 に答える
0

これは推定されないコンテキストであり、回避することはできません。

イテレータが与えられた場合、それがどの種類のコンテナに属しているかはおそらくわかりません。たとえば、生のポインターは、複数の種類のコンテナーのイテレーターとして機能する可能性があります。

幸いなことに、コンテナ型を何にも使用することはないので、破棄してイテレータでパラメータ化することができます。

しかし、コンテナに文字列が含まれていることを確認するために使用します!

いいえ、ありません。Foo<string>::iterator文字列への逆参照 (またはそれが存在すること)を教えてくれたのは誰ですか? もちろん、それが存在する場合は、既存の慣習により文字列に逆参照されている可能性がありますが、これは決して保証されません。

于 2014-02-03T18:52:19.337 に答える
0

問題は、const 以外の文字列beginend関数が を返しますstring::iteratorが、そうではないことstring::const_iteratorです。のみを使用して、同様の関数を作成する必要がありますstring::iterator。または、c++11 では、cbegin および cend 関数を使用できます。

于 2014-02-03T18:04:21.353 に答える