ジェネリック引数として特定のタイプを持つSTLコンテナー


25

特定のタイプのコンテナをstd::stringパラメータとして受け取る関数を作成する方法はありますか?

void foo(const std::container<std::string> &cont)
{
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

そして、入力としてすべてのタイプのstlコンテナーに対してそれを呼び出しますか?上記のように?

std::set<std::string> strset;
std::vector<std::string> strvec;
std::list<std::string> strlist;

foo(strset);
foo(strvec);
foo(strlist);

2
はい、それはテンプレート関数と呼ばれています。;)
Ulrich Eckhardt

2
多くの場合、1組のイテレーター(それぞれコンテナーの最初と最後の1つを表す)を渡す方がよいと考えられています。イテレーターが関数の要件を満たしている限り、イテレーターが取得されたコンテナーのタイプは関係ありません(多くの場合、いくつかの例外があります)。
ピーター

回答:


21

あなたは作ることができますfoo取る関数テンプレートテンプレートテンプレートパラメータをコンテナ型のために。

例えば

template<template<typename...> typename C>
void foo(const C<std::string> &cont)
{
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

住む


さらに一般化できると思います。私の答えを見てください。
theWiseBro

Larsの答えは、Cスタイルの配列でも機能するため、より優れています。
Ayxan

1
@theWiseBroはい、それは一般的に良い考えです。しかし、私はOPが特定のタイプでそれを使用したいだけだと思うstd::stringので、..
songyuanyao

3
@theWiseBro正確に。OPは、1つの特定のタイプで動作するはずだと述べました。したがって、さらに一般化するメリットはありません。
M.スピラー

1
@theWiseBro私はあなたの意味を理解しています。OPの本来の意図についてはよくわかりません。彼は特定のタイプを1つだけ欲しいと言っただけです。OPに説明する必要があるかもしれません。:)
songyuanyao

6

foo他のケースでオーバーロードするかどうかに応じて

// Doesn't participate in overload resolution when not applicable
template<typename Container, typename = std::enable_if_t<std::is_same_v<typename Container::value_type, std::string>>>
void foo(const Container &cont) {
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

// simpler
template<typename Container>
void foo(const Container &cont) {
   static_assert(std::is_same_v<typename Container::value_type, std::string>, "Container must contain std::string")
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

あなたは許可するstd::is_sameなどのために別のテストを使用するかもしれませんstd::is_convertible

std::vector<char *> c_strings;
foo(c_strings);

0

代わりにイテレータを使用することを検討してください。中間結果は次のようになります

template<typename Iter>
void foo(Iter begin, Iter end) {
  using T = decltype(*begin);
  std::for_each(begin, end, [] (cons T & t) {
    std::out << t << '\n';
  }
}

呼び出し可能なテンプレートを使用する:

template<typename Iter, typename Callable>
void foo(Iter begin, Iter end, Callable & c) {
  std::for_each(begin, end, c);
}

STLがすでに提供しているものを使用する方法を学びました。


-1

@songyuanyaoの答えに加えて、私はそれをさらに一般化して次のようにできると思います:

template<template<typename...> typename C, typename ... D>
void foo(const C<D...> &cont)
{
   for(const auto& val: cont) {
      std::cout << val << std::endl;
   }
}

1
これは要素タイプをstd :: stringに制限しないので、質問には答えません。
サーシャ

@Sashaこれはstd :: stringに固定されていないことは事実ですが、より一般化されています。OPは特定のタイプを使用したいと考えています。今日はstd :: stringを使用していて、明日は代わりにMyCustomStringを使用したいとします。彼はコードを1か所で編集するだけでよいので、これは保守が簡単になると思いませんか?
theWiseBro

しかし、これはそれを制限する方法を示していないのいずれか、具体的に「コンテナ撮りたかったquerent -のstd ::文字列またはMyCustomString要素の特定のタイプのを」。現状では、たまたまテンプレートであるすべての型を受け入れます。その時点で、なぜそれを単一の<typename C>でテンプレート化しないのですか?これははるかに単純で、少し一般化されています。たとえば、コンテナーはstd :: string(別名std :: basic_string <char>)をコンテナーとして受け取りますが、カスタム構造体MyCustomStringではないため、完全に汎用的ではありません。
サーシャ

また、関数が要素がstd :: stringであると想定している場合、ユーザーがstd :: tuple <int、double、std :: nullptr_t>を渡すことを許可すると、使用と保守が難しくなります。
サーシャ

@サーシャうーん。あなたの言ってる事がわかります。それは本当だ。ヘッドアップをありがとう!
theWiseBro
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.