Container STL với một loại cụ thể làm đối số chung


25

Có cách nào để tôi có thể tạo một hàm lấy một thùng chứa với một loại cụ thể (giả sử std::string) làm tham số không

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

và gọi nó cho mọi loại container stl làm đầu vào? như trên?

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

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

2
Đúng, nó được gọi là một hàm mẫu. ;)
Ulrich Eckhardt

2
Nó thường được coi là tốt hơn để vượt qua một cặp vòng lặp (tương ứng là bắt đầu và một quá khứ của container). Miễn là các trình vòng lặp đáp ứng các yêu cầu của hàm, nó (thường, có một số ngoại lệ) không quan trọng chúng được lấy từ loại container nào.
Peter

Câu trả lời:


21

Bạn có thể tạo foomẫu hàm lấy tham số mẫu mẫu cho loại vùng chứa.

ví dụ

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

TRỰC TIẾP


Tôi nghĩ rằng chúng ta có thể khái quát nó hơn nữa. Xem câu trả lời của tôi.
theWiseBro

Câu trả lời của Lars tốt hơn bởi vì nó cũng hoạt động với các mảng kiểu C.
Ayxan

1
@theWiseBro Vâng, nói chung đó là một ý tưởng tốt. Nhưng tôi nghĩ OP chỉ muốn sử dụng nó với loại cụ thể như std::stringvậy, vì vậy ..
songyuanyao

3
@theWiseBro chính xác. OP nói rằng nó nên hoạt động với một loại cụ thể . Do đó không có lợi ích để khái quát nó hơn nữa.
M. Spiller

1
@theWiseBro Tôi hiểu ý của bạn. Tôi không chắc về ý định ban đầu của OP, anh ta chỉ nói muốn một loại cụ thể; bạn có thể cần phải giải thích nó với OP. :)
songyuanyao

6

Tùy thuộc vào việc bạn có muốn quá tải foocho các trường hợp khác hay không

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

Bạn có thể sử dụng một thử nghiệm khác để std::is_same, chẳng hạn như std::is_convertiblecho phép

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

0

Bạn có thể muốn xem xét sử dụng các vòng lặp thay thế. Một kết quả trung gian có thể trông giống như

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

Hiện đang sử dụng một mẫu có thể gọi được:

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

Chúng tôi chỉ học cách sử dụng những gì STL đã cung cấp.


-1

Thêm vào câu trả lời của @ songyuanyao, tôi nghĩ chúng ta có thể khái quát nó hơn nữa để:

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

1
Điều này không giới hạn loại phần tử thành chuỗi std ::, vì vậy nó không trả lời câu hỏi.
Sasha

@Sasha Đúng là điều này không cố định với std :: string nhưng nó khái quát hơn. OP muốn sử dụng một loại cụ thể. Giả sử hôm nay anh ấy đang sử dụng std :: string và ngày mai anh ấy muốn sử dụng MyCustomString thay thế. Điều này có chứng tỏ việc bảo trì dễ dàng hơn không vì anh ta chỉ phải chỉnh sửa mã ở một nơi duy nhất?
theWiseBro

Nhưng điều này không thấy làm thế nào để hạn chế nó đến một trong hai std :: string hoặc các yếu tố MyCustomString - và querent đặc biệt muốn có "một container với một loại hình cụ thể ". Như vậy, nó sẽ chấp nhận bất kỳ loại nào xảy ra là một mẫu và tại thời điểm đó tại sao không chỉ tạo mẫu trên một <typename C> duy nhất? Điều đó đơn giản hơn và khái quát hơn một chút - ví dụ: bạn sẽ lấy std :: string (còn gọi là std :: basic_opes <char>) làm bộ chứa nhưng không phải là cấu trúc tùy chỉnh MyCustomString, vì vậy nó không hoàn toàn chung chung.
Sasha

Và nếu hàm mong muốn các phần tử là std :: string, cho phép người dùng vượt qua std :: tuple <int, double, std :: nullptr_t> khiến việc sử dụng và bảo trì khó khăn hơn .
Sasha

@Sasha hmm. Tôi thấy điểm của bạn. Đúng. Cảm ơn cho những người đứng đầu lên!
theWiseBro
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.