C ++“スマート” stlアルゴリズムの述語
質問
find_if、count_ifなどのstlアルゴリズムの述語を設計する必要があります。
namespace lib
{
struct Finder
{
Finder( const std::string& name ):
name_( name )
{
}
template< typename TElement >
bool operator( const TElement& element )
{
return element.isPresent( name_ );
}
/* template< typename TElement >
bool operator( const TElement& element )
{
const Data& data = element.getData();
return data.isPresent( name_ );
}*/
};
}
しかし、TElementの特定のメソッドの存在に応じて、異なる演算子()が必要です。 「getData」がある場合のようにそのデータを確認したいのですが、データがない場合は他のアクションを実行します。
SFINAEを知っています。しかし、私はboost ::がプロジェクトにありません。 したがって、テンプレート&quot; has_method&quot;の簡単な実装があります。または、他の設計ソリューションを知っている。
この述語をプロジェクトライブラリの1つに配置したいので、特定の型を指すことができず、単にオーバーロードします。メソッド。
名前空間がない限り、クラス特性を使用したソリューションは良好です。 &quot; lib&quot;の述語ファインダー&quot; getData&quot;を使用した名前空間とクラス「プログラム」にある名前空間。
ありがとう。
解決
テンプレートmathodを使用する理由基にする特定のクラス、またはクラスタイプが多数ある場合は共通の基本クラスを使用します。
e.g。
struct Finder
{
Finder( const std::string& name ):
name_( name )
{
}
bool operator( const IsPresentBaseClass& element )
{
return element.isPresent( name_ );
}
bool operator( const GetDataBaseClass& element )
{
const Data& data = element.getData();
return data.isPresent( name_ );
}
};
このパターンが異なるクラスタイプで頻繁に発生し、述語を使用する前にタイプを知っている場合、述語自体をテンプレート化できます。
e.g。
template<class T1, class T2>
struct Finder
{
Finder( const std::string& name ):
name_( name )
{
}
bool operator( const T1& element )
{
return element.isPresent( name_ );
}
bool operator( const T2& element )
{
const Data& data = element.getData();
return data.isPresent( name_ );
}
};
または使用できる別のアプローチは、何らかのクラス特性を使用して情報を保持することです。
e.g。
struct UseIsPresent
{
template<class T>
static bool CompareElement( const T& element, const std::string& name )
{
return element.isPresent( name );
}
};
struct UseGetData
{
template<class T>
static bool CompareElement( const T& element, const std::string& name )
{
const Data& data = element.getData();
return data.isPresent( name );
}
};
// default to using the isPresent method
template <class T>
struct FinderTraits
{
typedef UseIsPresent FinderMethodType;
};
// either list the classes that use GetData method
// or use a common base class type, e.g. UseGetData
template <>
struct FinderTraits<UseGetData>
{
typedef UseGetData FinderMethodType;
};
struct Finder
{
Finder( const std::string& name )
: name_( name )
{
}
template<class T>
bool operator()( const T& element )
{
return FinderTraits<T>::FinderMethodType::CompareElement<T>(element, name_);
}
std::string name_;
};
これらすべてのメソッドの欠点は、使用するメソッドに分割できるように、ある時点でタイプを知る必要があることです。
他のヒント
Veldhuizenのホームページ switch
テンプレート用。おそらくこれを使用して正確な演算子を選択できますか?
「機能タイプ」からタイプを派生させます。 (例えば、タイプ&quot; has_function1&quot;)これはJavaインターフェイスとして機能し、SFINAEを使用してあるタイプを別のタイプに変換できるかどうかをテストできるため、チャンスがあります。
もし興味があれば、私はそれを調べてより詳細な答えを与えることができます。
編集: Boostライブラリを使用できないと言っていましたが、boost :: is_convertibleを機能させるために必要ないくつかのファイルを取得できない原因はありますか?コンパイルするものは特にありません!
ブーストは魔法ではありません。 SFINAEの使用は非常に簡単です:
template< typename TElement >
bool operator( const TElement& element, ... )
{
return element.isPresent( name_ );
}
template< typename TElement >
bool operator( const TElement& element, const Data& data = element.getData())
{
return data.isPresent( name_ );
}
SFINAEは、コンパイルされない場合、2番目のオーバーロードを削除します。オーバーロード解決は、...がより悪い一致であるため、コンパイルする場合、2番目を選択します。