具有特定类型作为通用参数的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
是的,它称为模板函数。;)
Ulrich Eckhardt

2
通常认为最好传递一对迭代器(分别代表容器的开始和结束时间)。只要迭代器满足该功能的要求,它(通常会有一些例外情况)与从哪种容器中获取它们无关紧要。
彼得

Answers:


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

Lars的答案更好,因为它也适用于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';
  }
}

现在使用可调用模板:

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上,而是更通用的。OP希望使用特定类型。假设今天他使用std :: string,明天他想使用MyCustomString。因为他只需要在一个地方编辑代码,这样维护起来就容易吗?
theWiseBro

但是,这并不说明如何将其限制于任何的std :: string或MyCustomString元素-特别是要采取“一个容器中求卜者与特定类型 ”。照原样,它将接受碰巧是模板的任何类型,那么为什么不只在单个<typename C>上将其模板化呢?这要简单得多,而且泛化程度更高-例如,您将使用std :: string(也称为std :: basic_string <char>)作为容器,而不是自定义结构MyCustomString,因此它不是完全通用的。
萨沙

并且如果函数期望元素为std :: string,则允许用户传递std :: tuple <int,double,std :: nullptr_t>使其更难使用和维护。
萨沙

@Sasha嗯。我明白你的意思了。确实如此。感谢您的注意!
theWiseBro
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.