STL-Container mit einem bestimmten Typ als generisches Argument

25

Gibt es eine Möglichkeit, eine Funktion zu erstellen, die einen Container mit einem bestimmten Typ (z. B. std::string) als Parameter verwendet?

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

und es für jede Art von stl-Container als Eingabe aufrufen? wie oben?

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

foo(strset);
foo(strvec);
foo(strlist);
Chatzich
quelle
2
Ja, es heißt Vorlagenfunktion. ;)
Ulrich Eckhardt
2
Es wird oft als besser angesehen, ein Paar Iteratoren zu übergeben (die den Anfang bzw. das Ende des Containers darstellen). Solange Iteratoren die Anforderungen der Funktion erfüllen, spielt es keine Rolle (oft gibt es einige Ausnahmen), aus welcher Art von Containern sie stammen.
Peter

Antworten:

21

Sie können fooeine Funktionsvorlage erstellen, die einen Vorlagenvorlagenparameter für den Containertyp verwendet.

z.B

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

LEBEN

songyuanyao
quelle
Ich denke, wir können es noch weiter verallgemeinern. Siehe meine Antwort.
theWiseBro
Lars ' Antwort ist besser, da sie auch mit Arrays im C-Stil funktioniert.
Ayxan
1
@theWiseBro Ja, das ist im Allgemeinen eine gute Idee. Aber ich denke, OP möchte es nur mit einem bestimmten Typ verwenden std::string, also ...
songyuanyao
3
@theWiseBro genau. OP sagte, dass es mit einem bestimmten Typ funktionieren sollte . Daher gibt es keinen Vorteil, es weiter zu verallgemeinern.
M. Spiller
1
@theWiseBro Ich verstehe, was du meintest. Ich bin mir nicht sicher über die ursprüngliche Absicht von OP, er sagte nur, ich möchte einen bestimmten Typ; Möglicherweise müssen Sie es OP erklären. :)
songyuanyao
6

Abhängig davon, ob Sie foofür andere Fälle überladen möchten oder nicht

// 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;
   }
}

Sie können einen anderen Test verwenden std::is_same, std::is_convertibleum dies zuzulassen

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

Möglicherweise möchten Sie stattdessen Iteratoren verwenden. Ein Zwischenergebnis kann so aussehen

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';
  }
}

Verwenden Sie jetzt eine aufrufbare Vorlage:

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

Wir haben gerade gelernt, das zu nutzen, was die STL bereits bietet.

user1624886
quelle
-1

Ich denke, wir können die Antwort von @ songyuanyao weiter verallgemeinern, um:

template<template<typename...> typename C, typename ... D>
void foo(const C<D...> &cont)
{
   for(const auto& val: cont) {
      std::cout << val << std::endl;
   }
}
theWiseBro
quelle
1
Dadurch wird der Elementtyp nicht auf std :: string beschränkt, sodass die Frage nicht beantwortet wird.
Sasha
@ Sasha Es ist wahr, dass dies nicht auf std :: string festgelegt ist, aber es ist allgemeiner. Das OP möchte einen bestimmten Typ verwenden. Angenommen, er verwendet heute std :: string und möchte morgen stattdessen einen MyCustomString verwenden. Wäre dies nicht einfacher zu warten, da er den Code nur an einer einzigen Stelle bearbeiten muss?
theWiseBro
Aber das zeigt nicht , wie es zu beschränken auf beide std :: string oder MyCustomString Elemente - und das querent speziell nehmen „einen Container wollte mit einem bestimmten Typ “. So wie es ist, wird jeder Typ akzeptiert, der zufällig eine Vorlage ist, und an diesem Punkt, warum nicht einfach stattdessen eine Vorlage auf einem einzelnen <Typnamen C> erstellen? Das ist viel einfacher und etwas allgemeiner - z. B. wird bei Ihnen ein std :: string (auch bekannt als std :: basic_string <char>) als Container verwendet, jedoch keine benutzerdefinierte Struktur MyCustomString, sodass diese nicht vollständig generisch ist.
Sasha
Wenn die Funktion erwartet, dass die Elemente std :: string sind, wird die Verwendung und Wartung durch Benutzer schwieriger , wenn sie ein std :: tuple <int, double, std :: nullptr_t> übergeben können .
Sasha
@ Sasha hmm. Ich weiß, worauf du hinauswillst. Das stimmt. Danke für die Warnung!
theWiseBro