Wadah STL dengan jenis tertentu sebagai argumen umum

25

Apakah ada cara saya bisa membuat fungsi yang mengambil wadah dengan tipe tertentu (katakanlah std::string) sebagai parameter

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

dan menyebutnya untuk setiap jenis wadah stl sebagai input? seperti diatas?

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

foo(strset);
foo(strvec);
foo(strlist);
chatzich
sumber
2
Yap, ini disebut fungsi template. ;)
Ulrich Eckhardt
2
Seringkali dianggap lebih baik untuk melewatkan sepasang iterator (masing-masing mewakili awal dan satu-akhir-akhir wadah). Selama iterator memenuhi persyaratan fungsi, itu (seringkali, ada beberapa pengecualian) tidak masalah jenis wadah mereka berasal.
Peter

Jawaban:

21

Anda bisa membuat footemplat fungsi dengan mengambil parameter templat templat untuk tipe kontainer.

misalnya

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

HIDUP

songyuanyao
sumber
Saya pikir kita bisa menyamaratakan lebih jauh. Lihat jawaban saya.
theWiseBro
Jawaban Lars lebih baik karena ia juga bekerja dengan array gaya-C.
Ayxan
1
@ theWiseBro Ya itu ide yang bagus secara umum. Tapi saya pikir OP hanya ingin menggunakannya dengan tipe tertentu std::string, jadi ..
songyuanyao
3
@ theWiseBro tepatnya. OP mengatakan bahwa itu harus bekerja dengan satu tipe spesifik . Karena itu tidak ada manfaat untuk menggeneralisasikannya lebih lanjut.
M. Spiller
1
@ theWiseBro Saya mengerti maksud Anda. Saya tidak yakin tentang maksud asli OP, dia hanya mengatakan ingin satu tipe tertentu; Anda mungkin perlu menjelaskannya ke OP. :)
songyuanyao
6

Tergantung pada apakah Anda ingin kelebihan beban foountuk kasus lain atau tidak

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

Anda dapat menggunakan tes yang berbeda untuk std::is_same, seperti std::is_convertiblemengizinkan

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

Anda mungkin ingin mempertimbangkan untuk menggunakan iterator. Hasil antara mungkin terlihat seperti

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

Sekarang menggunakan templat yang dapat dipanggil:

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

Kami baru belajar menggunakan apa yang sudah ditawarkan STL.

pengguna1624886
sumber
-1

Menambahkan ke jawaban @ songyuanyao, saya pikir kita dapat menggeneralisasikannya lebih lanjut ke:

template<template<typename...> typename C, typename ... D>
void foo(const C<D...> &cont)
{
   for(const auto& val: cont) {
      std::cout << val << std::endl;
   }
}
theWiseBro
sumber
1
Ini tidak membatasi tipe elemen ke std :: string, jadi itu tidak menjawab pertanyaan.
Sasha
@ Sasha Memang benar ini tidak diperbaiki ke std :: string tetapi lebih umum. OP ingin menggunakan jenis tertentu. Katakan hari ini dia menggunakan std :: string dan besok dia ingin menggunakan MyCustomString sebagai gantinya. Tidakkah ini terbukti lebih mudah dipelihara karena ia hanya perlu mengedit kode di satu tempat?
theWiseBro
Tapi ini tidak menunjukkan bagaimana untuk membatasi untuk baik std :: string atau elemen MyCustomString - dan querent secara khusus ingin mengambil "wadah dengan jenis tertentu ". Seperti itu, ia akan menerima jenis apa pun yang menjadi templat, dan pada saat itu mengapa tidak hanya templat pada satu <fontename C> saja? Itu jauh lebih sederhana dan sedikit lebih umum - misalnya milik Anda akan mengambil std :: string (alias std :: basic_string <char>) sebagai wadah tetapi bukan struktur kustom MyCustomString, sehingga tidak sepenuhnya generik.
Sasha
Dan jika fungsi mengharapkan elemen menjadi std :: string, yang memungkinkan pengguna untuk mengirim std :: tuple <int, double, std :: nullptr_t> membuatnya lebih sulit untuk digunakan dan dipelihara.
Sasha
@Sasha hmm. Saya mengerti maksud Anda. Itu benar. Terimakasih atas peringatannya!
theWiseBro