Контейнер STL із специфічним типом як загальний аргумент


25

Чи я можу зробити функцію, яка приймає контейнер із певним типом (скажімо std::string) як параметр

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

і називати його для кожного типу контейнера stl як вхідного? як вище?

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

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

2
Так, це називається функцією шаблону. ;)
Ульріх Екхардт

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-стилі.
Айксан

1
@theWiseBro Так, це взагалі гарна ідея. Але я думаю, що ОП просто хоче використовувати його з певним типом як std::string, так ..
songyuanyao

3
@theWiseBro точно. ОП заявила, що вона повинна працювати з одним конкретним типом . Тому немає користі додатково узагальнювати це.
М. Спіллер

1
@theWiseBro Я розумію, що ти мав на увазі. Я не впевнений у первісному намірі ОП, він просто сказав, що хочу одного конкретного типу; вам може знадобитися пояснити це ОП. :)
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';
  }
}

Тепер використовуємо шаблон для дзвінка:

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 Це правда, що це не виправлено на std :: string, але це більш узагальнено. ОП хоче використовувати конкретний тип. Скажіть, сьогодні він використовує std :: string, а завтра він хоче використовувати MyCustomString. Чи не виявиться це простішим у обслуговуванні, оскільки він повинен лише редагувати код в одному місці?
theWiseBro

Але це не показано , як обмежити його або станд :: рядок або MyCustomString елементів - і кверента спеціально хотів взяти «контейнер з типом конкретного ». Отже, він прийме будь-який тип, який трапляється як шаблон, і чому тоді не просто шаблонувати його на одному <typename C> замість? Це набагато простіше і трохи більш узагальнено - наприклад, ваш буде використовувати контейнер std :: (ака std :: basic_string <char>) як контейнер, але не користувацьку структуру MyCustomString, тому це не є повністю загальним.
Сашко

І якщо функція очікує, що елементи будуть std :: string, що дозволяє користувачам передавати std :: tuple <int, double, std :: nullptr_t>, це ускладнює використання та підтримку.
Сашко

@ Саша хм. Я бачу вашу думку. Це правда. Дякую за голову вгору!
theWiseBro
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.