C ++函数填充和打印任意容器

时间:2018-08-27 21:32:18

标签: templates stl

在学习C ++时,我想编写一些函数来

  • 填充任意容器
  • 打印任意容器的值

到目前为止,我设法为任意容器编写了第二个函数,但没有为第一个函数编写。

打印功能:

template <class C>
void printMyContainer(C v) {
  for (auto it = v.begin(); it != v.end(); it++)
    std::cout << std::setw(3) << *it << " ";    
    std::cout << std::endl;
}

填写功能:

template <typename T>
using in = typename std::istream_iterator<T>;

template <class C, typename T>
C fillInMyContainer(C v) {
    std::cout << "Enter values:"<<std::endl;        
    std::for_each(in<T>(std::cin), in<T>(), 
    [&](T a) { v.push_back(a); });
    return v;
}

现在,填充函数具有一种push_back方法,这对于 all 容器来说并不常见。

因此,我想知道

  • 如何将填充函数传递到fillInMyContainer函数中?我试图做类似的事情:

    template <class C, typename T>
    C fillInMyContainer(C v, void (*f)(T)) {
      std::for_each(in<T>(std::cin), in<T>(),
      [&](T a) { (*f)(a); });
      return v;
    }
    
  • 已经有这样的模板了吗?

1 个答案:

答案 0 :(得分:0)

首先,打印(您的打印方式)可以稍微紧凑一些:

#include <iostream>
#include <iterator>

template<class C> std::ostream &printContainer(std::ostream &s, C const &c) {
     std::copy(c.begin(), c.end(), std::ostream_iterator<typename C::value_type>(s, " "))
         << '\n';
}

这并不重要。现在,要将元素添加到任意容器中,您可以使用SFINAE的奇迹:

template<class C, class T>
decltype(std::declval<C>().insert(std::declval<T>()), C{}) fillContainer(C c) {
    std::for_each(in<T>(std::cin), in<T>(), [&c](T const &t){ c.insert(t); });
    return c;
}

也许甚至

template<class C>
decltype(std::declval<C>().insert(std::declval<typename C::value_type>()), std::declval<C &>()) fillContainer(C &c) {
    using T = typename C::value_type;
    std::for_each(in<T>(std::cin), in<T>(), [&c](T const &t){ c.insert(t); });
    return c;
}

decltype之后括号内的内容是未评估上下文中的逗号运算符。如果在单独的一行上单独找到这样的表达式,就永远不会构建程序(例如,std::declval没有定义),而只是作为要检查类型有效性的表达式就可以了。因此,仅在c.insert(t)编译时(以及在逗号给我们提供函数的返回类型后C{}编译时才选择此重载。)对于向量(或字符串),可以添加另一个:

template<class C, class T>
auto fillContainer(C c) -> decltype(c.push_back(std::declval<T>()), C{});

(在这里,我已经将SFINAEing decltype放入尾随的返回类型,在这种情况下,这为我们节省了对std::declval的一次调用,因为到目前为止,我们已经拥有{{1} }类型为c,因此我们不需要调用C来创建对std::declval的引用。)