私は、メソッドのようなものを因数分解するためのテクニックを探しています。問題は次のとおりです。検索を行うためにコンテナの内容を変更する必要のないコンテナのfindメソッドが必要です。ただし、const_iteratorの代わりにイテレータが返された場合にコンテナが変更される可能性があるため、constバージョンとnon-constバージョンが存在する必要があります。これらの2つのケースでは、コードはまったく同じであり、アクセサーのみがconstXXXまたはXXXに評価され、コンパイラーがその役割を果たします。設計と保守の観点から見ると、これら2つの方法を2回実装するのは賢明ではありません。(そして、そのためにマクロを使用することは本当に避けたいです...)私が意味することは、stl_tree.hのstlのgcc実装からのそのコードによっても非常によく示されています。
template<typename _Key, typename _Val, typename _KeyOfValue,
typename _Compare, typename _Alloc>
typename _Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::iterator
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
find(const _Key& __k)
{
iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
return (__j == end()
|| _M_impl._M_key_compare(__k,
_S_key(__j._M_node))) ? end() : __j;
}
template<typename _Key, typename _Val, typename _KeyOfValue,
typename _Compare, typename _Alloc>
typename _Rb_tree<_Key, _Val, _KeyOfValue,
_Compare, _Alloc>::const_iterator
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
find(const _Key& __k) const
{
const_iterator __j = _M_lower_bound(_M_begin(), _M_end(), __k);
return (__j == end()
|| _M_impl._M_key_compare(__k,
_S_key(__j._M_node))) ? end() : __j;
}
メソッドのプロトタイプは異なりますが、実装で記述されたコードは実際には同じであることがわかります。
私は2つの可能な解決策を思いつきました。1つはconst_castを使用する方法で、もう1つはヘルパーテンプレート構造体を使用する方法です。ここでは、これら2つのアプローチの簡単な例を示しました。
#include <iostream>
using namespace std;
struct Data
{
typedef int* iterator;
typedef const int* const_iterator;
int m;
Data():m(-3){}
};
struct A : public Data
{
const_iterator find(/*const Key& k */) const
{
A *me = const_cast < A* > ( this );
return const_iterator( me->find(/*k*/) );
}
iterator find(/*const Key& k */){
return &m; }
};
//the second one is with the use of an internal template structure:
struct B : public Data
{
template<class Tobj, class Titerator>
struct Internal
{
Titerator find( Tobj& obj/*, const Key& k */ ){
return &(obj.m); }
};
const_iterator find( /*const Key& k */ ) const
{
Internal<const B, const_iterator> internal;
return internal.find( *this/*, k*/ );
}
iterator find( /*const Key& k */ )
{
Internal<B,iterator> internal;
return internal.find( *this/*, obs*/ );
}
};
int main()
{
{
A a;
a.find();
A::iterator it = a.find();
cout << *it << endl;
const A& a1(a);
A::const_iterator cit = a1.find();
cout << *cit << endl;
}
{
B b;
b.find();
B::iterator it = b.find();
cout << *it << endl;
const B& b1(b);
B::const_iterator cit = b1.find();
cout << *cit << endl;
}
}
これはおそらく非常によく知られている問題であり、C++の第一人者がその問題を修正するための優れたデザインパターンを考え出すかどうかを知りたいと思います。特に、これら2つのアプローチのいずれかで(特にパフォーマンスの観点から)問題が発生したかどうかを知りたいと思います。最初のものははるかに理解しやすいので、特にそれを読んだ後は、それを好むでしょう: 定数とC ++ でのコンパイラの最適化により、const_castを記述してパフォーマンスを損なうことを恐れないようです。
よろしくお願いします、乾杯、
マヌエル