Genel bir bağımsız değişken olarak belirli bir türe sahip STL kapsayıcısı


25

Ben std::stringparametre olarak belirli bir tip (diyelim ) ile bir kap alır bir işlevi yapmak herhangi bir yolu var mı

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

ve her stl konteyneri için girdi olarak çağır? yukarıdaki gibi?

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

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

2
Evet, buna şablon fonksiyonu denir. ;)
Ulrich Eckhardt

2
Genellikle bir çift yineleyiciyi geçmek daha iyidir (sırasıyla kabın başlangıcını ve sonunu bir kez temsil eder). Yineleyiciler işlevin gereksinimlerini karşıladığı sürece, (genellikle bazı istisnalar vardır) ne tür kaplardan elde edildikleri önemli değildir.
Peter

Yanıtlar:


21

Kapsayıcı türü için şablon şablonu parametresifoo alarak bir işlev şablonu yapabilirsiniz .

Örneğin

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

CANLI


Bence onu daha da genelleştirebiliriz. Cevabımı gör.
theWiseBro

Lars'ın cevabı daha iyidir çünkü C tarzı dizilerle de çalışır.
Ayxan

1
@theWiseBro Evet genel olarak iyi bir fikir. Ama bence OP sadece gibi belirli bir std::string
tiple

3
@theWiseBro tam olarak. OP, bunun belirli bir türle çalışması gerektiğini söyledi . Bu nedenle onu daha genelleştirmenin bir yararı yoktur.
M. Spiller

1
@theWiseBro Ne demek istediğini anlıyorum. OP'nin orijinal amacından emin değilim, sadece belirli bir tip istediğini söyledi; OP'ye açıklamanız gerekebilir. :)
songyuanyao

6

fooDiğer durumlar için aşırı yüklenmek isteyip istemediğinize bağlı olarak

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

Sen farklı bir testi kullanabilir std::is_same, örneğin std::is_convertibleizin

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

0

Bunun yerine yineleyicileri kullanmayı düşünebilirsiniz. Ara sonuç şuna benzeyebilir

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

Şimdi çağrılabilir bir şablon kullanıyor:

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

STL'nin sunduklarını kullanmayı öğrendik.


-1

@ Songyuanyao'nun cevabına ek olarak, daha da genelleştirebileceğimizi düşünüyorum:

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

1
Bu öğe türünü std :: string ile sınırlamaz, bu yüzden soruyu cevaplamaz.
Sasha

@Sasha Bunun std :: string ile sabit olmadığı doğru ama daha genel. OP belirli bir tür kullanmak istiyor. Bugün std :: string kullandığını ve yarın bunun yerine MyCustomString kullanmak istediğini söyle. Kodu tek bir yerde düzenlemek zorunda kaldığı için bunun bakımı daha kolay olmaz mıydı?
theWiseBro

Ama bu onu kısıtlamak için nasıl göstermez ya ve özellikle "bir kap almak istedim querent - std :: string veya MyCustomString elemanları belirli bir tip ". Olduğu gibi, bir şablon olan herhangi bir türü kabul eder ve bu noktada bunu neden yalnızca tek bir <typename C> üzerinde şablonlamıyorsunuz? Bu çok daha basit ve biraz daha genelleştirilmiş - örneğin sizinki konteyner olarak bir std :: string (aka std :: basic_string <char>) alacak, ancak MyCustomString özel bir yapı değil, bu yüzden tamamen genel değil.
Sasha

İşlev, öğelerin std :: string olmasını beklerse, kullanıcıların bir std :: tuple <int, double, std :: nullptr_t> iletmesini sağlayarak kullanımını ve bakımını zorlaştırır .
Sasha

@Sasha hmm. Senin değinmek istediğin noktayı anlıyorum. Bu doğru. Söylediğin için teşekkürler!
theWiseBro
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.