คอนเทนเนอร์ STL ที่มีประเภทเฉพาะเป็นอาร์กิวเมนต์ทั่วไป


25

มีวิธีที่ฉันสามารถสร้างฟังก์ชั่นที่ใช้ภาชนะที่มีประเภทเฉพาะ (ขอพูดstd::string) เป็นพารามิเตอร์

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

และเรียกมันว่า stl container ทุกชนิดเป็น input หรือไม่? ชอบข้างบน?

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
มันมักจะถือว่าดีกว่าที่จะผ่านคู่ของตัววนซ้ำ (แทนจุดเริ่มต้นและหนึ่งในอดีตที่ผ่านมาของภาชนะตามลำดับ) ตราบใดที่ตัววนซ้ำตอบสนองความต้องการของฟังก์ชั่นมัน (บ่อยครั้งที่มีข้อยกเว้นบางอย่าง) ไม่สำคัญว่าจะได้รับภาชนะประเภทใด
ปีเตอร์

คำตอบ:


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

ลาร์ส คำตอบนั้นดีกว่าเพราะมันใช้ได้กับอาร์เรย์แบบ C
Ayxan

1
@TheWiseBro ใช่มันเป็นความคิดที่ดีโดยทั่วไป แต่ฉันคิดว่า OP ต้องการใช้กับประเภทเฉพาะเป็นstd::stringดังนั้น ..
songyuanyao

3
@ theWiseBro อย่างแน่นอน OP บอกว่าควรทำงานด้วยประเภทใดประเภทหนึ่งโดยเฉพาะ ดังนั้นจึงไม่มีประโยชน์ที่จะพูดคุยเพิ่มเติม
M. Spiller

1
@theWiseBro ฉันเข้าใจว่าคุณหมายถึงอะไร ฉันไม่แน่ใจเกี่ยวกับเจตนาดั้งเดิมของ OP เขาแค่บอกว่าต้องการประเภทหนึ่ง คุณอาจต้องอธิบายให้ 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';
  }
}

ตอนนี้ใช้เทมเพลต callable:

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

@Sasha มันเป็นความจริงที่ว่านี่ไม่ได้ถูกกำหนดเป็น std :: string แต่มันถูกทำให้เป็นแบบทั่วไปมากกว่า OP ต้องการใช้ประเภทเฉพาะ สมมติว่าวันนี้เขาใช้ std :: string และพรุ่งนี้เขาต้องการใช้ MyCustomString แทน สิ่งนี้จะพิสูจน์ได้ง่ายกว่าในการรักษาเพราะเขาเพียงแค่ต้องแก้ไขรหัสในที่เดียว?
theWiseBro

แต่นี้ไม่ได้แสดงให้เห็นว่าการ จำกัด การมันทั้งมาตรฐาน :: สตริงหรือ MyCustomString องค์ประกอบ - และถามคนต้องการเฉพาะที่จะใช้ "ภาชนะที่มีประเภทที่เฉพาะเจาะจง " ตามที่เป็นอยู่มันจะยอมรับประเภทใดก็ตามที่เกิดขึ้นเป็นเทมเพลตและ ณ จุดนั้นเหตุใดจึงไม่ใช่แค่เทมเพลตใน <typename C> เดียวแทน นั่นง่ายกว่าและมีลักษณะทั่วไปมากกว่าเล็กน้อย - เช่นคุณจะใช้ std :: string (aka std :: basic_string <char>) เป็นที่บรรจุ แต่ไม่ใช่ struct MyCustomString ที่กำหนดเองดังนั้นจึงไม่ใช่แบบทั่วไป
Sasha

และถ้าฟังก์ชันคาดว่าองค์ประกอบจะเป็น std :: string การอนุญาตให้ผู้ใช้ส่งผ่าน std :: tuple <int, double, std :: nullptr_t> ทำให้การใช้และบำรุงรักษาทำได้ยากขึ้น
Sasha

@Sasha อืม ฉันเห็นประเด็นของคุณ นั่นเป็นเรื่องจริง ขอบคุณสำหรับหัวขึ้น!
theWiseBro
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.