STLコンテナに適したシンプルなC ++テンプレート
-
03-07-2019 - |
質問
完璧に機能するこのようなテンプレートが必要です
template <typename container> void mySuperTempalte (const container myCont)
{
//do something here
}
次に、上記のテンプレートをstd :: stringに特化したいので、思いつきました
template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
//check type of container
//do something here
}
これは機能せず、エラーをスローします。私は2番目の例を動作させたいのですが、可能であれば、テンプレートにいくつかのコードを追加して、std :: vector / std :: deque / std :: listが使用されているかどうかを確認し、それぞれで何かをしたいと思います場合。 コードの99%がベクターと両端キューの両方で同じであるため、テンプレートを使用しました。
解決
問題を正しく理解している場合、STLコンテナvector、dequeなどで機能するアルゴリズムがありますが、stringのテンプレート特化を記述しようとしています。この場合、質問で定義した一般化されたテンプレート化されたメソッドを書くことができます:-
template<typename container> void mySuperTempalte( const container &myCont )
{
// Implement STL container code
}
次に、宣言する文字列の特殊化について:-
template<> void mySuperTempalte( const container<std::string> &myCont )
{
// Implement the string code
}
その他の特殊化については、myContの型宣言を変更するだけです。ベクトルコンテナとデックコンテナに対して本当にこれを行う必要がある場合は、9月に提案されているように、コンテナ自体ではなく、テンプレートパラメータをそのコンテナ内の型のパラメータにします。
template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
// check type of container
// do something here
}
最初の実装をすべてのSTLコンテナで動作させて作業を簡単にすることで、これを回避する価値があります。その後、文字列クラスの特殊化のみが必要です。文字列をベクトルに変換して、特殊化をすべて回避することも検討してください。
副次的に、コンテナパラメータをconst参照に変更しました。とにかくオブジェクトconstを宣言する際に、これがあなたの望むものであると仮定します。
他のヒント
特化するには:
template<> void mySuperTempalte<std:string>(const std::string myCont)
{
//check type of container
//do something here
}
ベクターに特化するには:
template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
//check type of container
//do something here
}
dequeに特化するには:
template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
//check type of container
//do something here
}
テンプレートのtypenameパラメータを試しましたか?このようなコンテナを宣言するために使用される構文をエミュレートするため、構文は少し奇妙です。これについて詳しく説明している InformITの記事があります。
template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}
引数を参照として宣言する必要があることに注意してください!
ところで:このコメント
//check type of container
は、あなたが何か間違ったことをしているという死んだ景品です。コンテナのタイプを確認したくない 。代わりに、9月の回答に示すように、ユーザーはより洗練されたオーバーロードを行います。
これまでの回答は役立つように見えますが、別の構成を使用すると思います。 STLコンテナと同じように、すべてのコンテナがvalue_typeを定義することを期待しています。したがって、私は書くことができます
inline template <typename C> void mySuperTemplate (C const& myCont)
{
mySuperTemplateImpl<C, typename C::value_type>(myCont);
}
一般に、明示的に抽出したパラメーターを操作する方が簡単です。
@sep
「シンプルな」ソリューション
「sep」によって投稿された答えはかなり良いです。おそらくアプリ開発者の99%には十分でしょうが、ライブラリインターフェイスの一部である場合は、いくつかの改善を繰り返して使用できます。
ベクターに特化するには:
template<typename C> void mySuperTempalte (std::vector<C> myCont) { //check type of container //do something here }
これは、呼び出し元がstd :: vectorを使用していない場合に機能します。これがベクトルやリストなどに特化して十分に機能する場合は、ここで停止して使用してください。
より完全なソリューション
まず、関数テンプレートを部分的に特殊化することはできないことに注意してください-オーバーロードを作成できます。そして、それらの2つ以上が同じ程度に一致する場合、「アンビエントなオーバーロード」が発生します。エラー。そのため、サポートするすべてのケースで1つのマッチを作成する必要があります。
これを行うための1つの手法は、enable_if手法を使用することです-enable_ifでは、あいまいな言語ルールを使用して、可能な一致リストから関数テンプレートのオーバーロードを選択的に取り出すことができます...基本的に、ブール式がfalseの場合、オーバーロードは「見えない」。興味がある場合は、SFINAEで詳細を確認してください。
例。このコードは、エラーなしでMinGW(g ++ parameterize.cpp)またはVC9(cl / EHsc parameterize.cpp)を使用してコマンドラインからコンパイルできます。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };
template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };
namespace detail{
// our special function, not for strings
// use ... to make it the least-prefered overload
template <class Container>
void SpecialFunction_(const Container& c, ...){
cout << "invoked SpecialFunction() default\n";
}
// our special function, first overload:
template <class Container>
// enable only if it is a container of mutable strings
typename enable_if<
is_same<typename Container::value_type, string>::value,
void
>::type
SpecialFunction_(const Container& c, void*){
cout << "invoked SpecialFunction() for strings\n";
}
}
// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
detail::SpecialFunction_(c, 0);
}
int main(){
vector<int> vi;
cout << "calling with vector<int>\n";
SpecialFunction(vi);
vector<string> vs;
cout << "\ncalling with vector<string>\n";
SpecialFunction(vs);
}
出力:
d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default
calling with vector<string> invoked
SpecialFunction() for strings
d:\scratch>
それが良いデザインであるかどうかは、さらなる議論のために残されています。とにかく、部分的なテンプレートの特殊化を使用して、コンテナのタイプを検出できます。特に:
enum container_types
{
unknown,
list_container,
vector_container
};
template <typename T>
struct detect_container_
{
enum { type = unknown };
};
template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
enum { type = vector_container };
};
template <typename V>
struct detect_container_< std::list<V> >
{
enum { type = list_container };
};
// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
return static_cast<container_types>( detect_container_<T>::type );
}
int main()
{
std::vector<int> v;
assert( detect_container( v ) == vector_container );
}