【问题标题】:STL container with a specific type as a generic argument具有特定类型作为泛型参数的 STL 容器
【发布时间】:2020-06-03 10:52:46
【问题描述】:

有什么方法可以让我创建一个函数,它将具有特定类型的容器(比如说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);

【问题讨论】:

  • 是的,它被称为模板函数。 ;)
  • 通常认为传递一对迭代器更好(分别代表容器的开始和结束)。只要迭代器满足函数的要求,(通常有一些例外)它们是从什么类型的容器中获取的并不重要。

标签: c++ templates stl containers


【解决方案1】:

您可以将foo 设为函数模板,将template template parameter 用作容器类型。

例如

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

LIVE

【讨论】:

  • 我认为我们可以进一步概括它。看我的回答。
  • Lars' answer 更好,因为它也适用于 C 风格的数组。
  • @theWiseBro 是的,总的来说这是个好主意。但我认为 OP 只是想使用特定类型作为std::string,所以..
  • @theWiseBro 完全正确。 OP 说它应该适用于一种特定类型。因此,进一步概括它没有任何好处。
  • @theWiseBro 我明白你的意思。我不确定 OP 的初衷,他只是说想要一种特定的类型;您可能需要向 OP 解释它。 :)
【解决方案2】:

取决于您是否要在其他情况下重载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);

【讨论】:

    【解决方案3】:

    您可能需要考虑使用迭代器。中间结果可能看起来像

    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 已经提供的功能。

    【讨论】:

      【解决方案4】:

      加上@songyuanyao的回答,我想我们可以进一步概括为:

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

      【讨论】:

      • 这不会将元素类型限制为 std::string,因此它不会回答问题。
      • @Sasha 确实,这并不固定在 std::string 上,但它更通用。 OP想要使用特定类型。假设今天他使用 std::string ,明天他想使用 MyCustomString 。因为他只需要在一个地方编辑代码,这不是更容易维护吗?
      • 但这并没有显示如何将其限制为 either std::string 或 MyCustomString 元素 - 并且询问者特别想采用“一个容器 with a特定类型”。照原样,它会接受任何碰巧是模板的类型,那么为什么不直接在单个 上进行模板化呢?这要简单得多,也更通用-例如您的将采用 std::string(又名 std::basic_string)作为容器,但不是自定义结构 MyCustomString,因此它不是完全通用的。
      • 如果函数期望元素是std::string,允许用户传递std::tuple 使得它更难 使用和维护。
      • @Sasha 嗯。我明白你的意思。确实如此。感谢您的提醒!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-19
      • 1970-01-01
      • 2022-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多