如何使函数参数容器独立

时间:2011-03-27 18:25:03

标签: c++ templates iterator

我正在编写一个实用程序函数,它将采用元素向量(可以是string,int,double,char)并连接成一个字符串并返回它。它看起来像这样:

template<typename T>
std::string convert2Str(std::vector<T> const& vec) 
{
   std::ostringstream sStream; 
   for (size_t k=0; k<vec.size(); ++k) {
      sStream << vec[k] << " "; 
   }
   return sStream.str(); 
}

我想让这个功能更通用:

  • 首先使用迭代器而不是使用vector<T>的索引。我试过这个 在循环之前std::vector<T>::const_iterator it = vec.begin()并且编译器给了我一个错误: :错误:预期;之前 当我将上述定义更改为std::vector<std::string>::const_iterator it = vec.begin()时,错误消失了。所以,看起来我没有遵循正确的语法,请让我知道它是什么
  • 其次是通过使第一个参数容器独立来使函数更通用。给定任何容器(vectorlistqueuedeque等)我想做与上面相同的事情。我尝试在stackoverflow中搜索这个并没有找到满意的答案。

5 个答案:

答案 0 :(得分:5)

第1步,如你所说,使用迭代器:

template<typename T>
std::string convert2Str(std::vector<T> const& vec) 
{
   typedef std::vector<T> container;
   std::ostringstream sStream; 
   for (typename container::const_iterator it = vec.begin(); it != vec.end(); ++it) {
      sStream << *it << " "; 
   }
   return sStream.str(); 
}

步骤2,使模板参数成为容器类型而不是元素类型(您可以使用value_type返回元素类型:

template<typename container>
std::string convert2Str(container const& vec)
{
   typedef container::value_type T; // if needed
   std::ostringstream sStream; 
   for (typename container::const_iterator it = vec.begin(); it != vec.end(); ++it) {
      sStream << *it << " "; 
   }
   return sStream.str(); 
}

在C ++ 0x中,这变得更简单(并且不需要typename):

template<typename container>
std::string convert2Str(container const& vec)
{
   using std::begin;
   using std::end;
   std::ostringstream sStream;
   for (auto it = begin(vec); it != end(vec); ++it) {
      typedef decltype(*it) T; // if needed
      sStream << *it << " "; 
   }
   return sStream.str(); 
}

除其他优点外,std::beginstd::end适用于原始数组。

答案 1 :(得分:5)

遵循STL练习,我建议使用两个迭代器作为输入参数,而不是容器(因为明显的原因是只能使用容器的一部分,通常使用迭代器定义的任何序列):

template<typename InputIterator>
std::string convert2Str(InputIterator first, InputIterator last)
{
    std::ostringstream sStream;
    for (InputIterator it = first; it != last; ++it) {
       sStream << *it << " ";
    }
    return sStream.str();
}

如果您需要包含对象的类型,请使用

typedef typename std::iterator_traits<InputIterator>::value_type T;

增加: 然后,您可以按如下方式使用该功能:

std::vector<int> int_vec;
std::list<float> f_list;
std::deque<std::string> str_deq;

     // put something into the containers here

std::cout<< convert2Str(int_vec.begin(), int_vec.end()) <<std::endl;
std::cout<< convert2Str(f_list.begin(), f_list.end()) <<std::endl;
std::cout<< convert2Str(str_deq.begin(), str_deq.end()) <<std::endl;

请注意,您无法遍历std :: queue;但如果您确实需要它,该标准可确保为自己动手解决方案提供足够的支持。在此处查看更多信息:std::queue iteration

答案 2 :(得分:3)

如果你只对容器类型进行模板化,这是最简单的;值类型作为typedef成员value_type存储在所有标准Boost和Qt容器中。 std::copyostream_iterator允许您跳过冗长的迭代器声明。

template <typename Container>
std::string convert2Str(Container const &cont)
{
    std::ostringstream s;
    std::copy(cont.begin(), cont.end(),
              std::ostream_iterator<typename Container::value_type>(s, " "));
    return s.str();
}

typename是避免歧义所必需的。当您省略此关键字时,最新版本的GCC会发出警告。

答案 3 :(得分:2)

使用它。你需要typename部分来告诉编译器它在解析时应该考虑T::const_iterator一个类型,它实际上不能知道这是真的,直到你实际调用函数传递一些{{1有T成员类型。

const_iterator

答案 4 :(得分:0)

我认为这应该有效:

template<typename T>
std::string convert2Str(T const& container) 
{
   std::ostringstream sStream; 
   for (typename T::const_iterator i= container.begin(); i != container.end(); ++i) {
      sStream << *i << " "; 
   }
   return sStream.str(); 
}

演示:http://ideone.com/9pUVV