Nawaz's answer is likely the right solution for most cases. However, if you're trying to do this for many instantiated SomeContainerFromAThirdPartyLib
classes and only a few functions (or an unknown number of instantiations but a fixed number of functions, as might happen if you're writing your own library), there's another way.
次の(変更不可能な)コードが与えられているとします。
namespace ThirdPartyLib
{
template
class SomeContainerFromAThirdPartyLib
{
public:
typedef T ValueType; // not value_type!
// no difference_type
class iterator
{
public:
typedef T ValueType; // not value_type!
// no difference_type
//obviously this is not how these would actually be implemented
int operator != (const iterator& rhs) { return 0; }
iterator& operator ++() { return *this; }
T operator *() { return T(); }
};
//obviously this is not how these would actually be implemented
iterator begin() { return iterator(); }
iterator end() { return iterator(); }
};
}
iterator_traits
に必要な typedef
を含むアダプタクラステンプレートを定義し、ポインタの問題を避けるためにそれを特化します:
namespace MyLib
{
template
class iterator_adapter : public T
{
public:
//replace the following with the appropriate types for the third party iterator
typedef typename T::ValueType value_type;
typedef std::ptrdiff_t difference_type;
typedef typename T::ValueType* pointer;
typedef typename T::ValueType& reference;
typedef std::input_iterator_tag iterator_category;
explicit iterator_adapter(T t) : T(t) {}
};
template
class iterator_adapter
{
};
}
次に、 SomeContainerFromAThirdPartyLib :: iterator
を使用して呼び出せるようにする関数ごとに、オーバーロードを定義してSFINAEを使用します。
template
typename MyLib::iterator_adapter::difference_type
count(iter begin, iter end, const typename iter::ValueType& val)
{
cout << "[in adapter version of count]";
return std::count(MyLib::iterator_adapter(begin), MyLib::iterator_adapter(end), val);
}
次に、次のように使用できます。
int main()
{
char a[] = "Hello, world";
cout << "a=" << a << endl;
cout << "count(a, a + sizeof(a), 'l')=" << count(a, a + sizeof(a), 'l') << endl;
ThirdPartyLib::SomeContainerFromAThirdPartyLib container;
cout << "count(container.begin(), container.end(), 0)=";
cout << count(container.begin(), container.end(), 0) << std;
return 0;
}
include と using
を使用して、 > http://ideone.com/gJyGxU をご覧ください。出力:
a=Hello, world
count(a, a + sizeof(a), 'l')=3
count(container.begin(), container.end(), 0)=[in adapter version of count]0
残念ながら、警告があります:
- 前述したように、サポートする予定の関数(
find
、 sort
など)ごとにオーバーロードを定義する必要があります。これは明らかにまだ定義されていないアルゴリズム
の関数では機能しません。
- 最適化されていない場合は、実行時のパフォーマンスが低下する可能性があります。
- スコープの問題が考えられます。
その最後のものに関しては、どの名前空間でオーバーロードするのか(そして std
のバージョンを呼び出す方法)という質問があります。理想的には、 ThirdPartyLib
にあるので、引数に依存する検索で見つけることができますが、私はそれを変更できないと想定しています。次の最適なオプションは MyLib
ですが、呼び出しを修飾するか、 using
する必要があります。どちらの場合でも、エンドユーザは std :: count;
を使用するか、 std ::
:count が誤って SomeContainerFromAThirdPartyLib :: iterator
で使用されていると、明らかに失敗します(この演習の全理由)。
私が提案しないという代替案は、完全性のためにここに提示すると、 std
名前空間に直接配置することです。これは未定義の動作を引き起こします。それはあなたのために働くかもしれませんが、それを保証する何も標準にありません。オーバーロードするのではなく count
に特化していれば、これは正当なものです。