如何使函数参数容器独立

发布于 2024-10-26 23:50:07 字数 850 浏览 2 评论 0原文

我正在编写一个实用函数,它将采用元素向量(可以是 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 的索引。我试过这个 std::vector::const_iterator it = vec.begin() 在循环之前,编译器给了我一个错误: : 错误:在其之前应有 ; 当我将上述定义更改为 std::vector::const_iterator it = vec.begin() 错误消失。因此,看起来我没有遵循正确的语法,请让我知道它是什么。
  • 其次是通过使第一个参数容器独立来使函数更加通用。给定任何容器(vectorlistqueuedeque等)我想做同样的事情如上所述。我尝试在 stackoverflow 中搜索此内容,但没有找到满意的答案。

I'm writing a utility function which will take a vector of elements (could be string, int, double, char) and concatenate into a single string and return it. It looks like this:

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(); 
}

I would like to make this function more generic:

  • First use iterators instead of using indices for the vector<T>. I tried this
    std::vector<T>::const_iterator it = vec.begin() before the loop and the compiler gave me an error:
    : error: expected ; before it
    When I change the above defintions to std::vector<std::string>::const_iterator it = vec.begin() the error goes away. So, it looks like I'm not following correct syntax, please let me know what it is
  • Second is to make the function more generic by making the first argument container independent. Given any container (vector, list, queue, deque, etc.) I want to do the same thing as above. I tried searching for this in stackoverflow and did not find satisfactory answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

芸娘子的小脾气 2024-11-02 23:50:07

步骤 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 适用于原始数组。

Step 1, as you said, use iterators:

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(); 
}

Step 2, make the template argument the container type instead of the element type (you can get the element type back with 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(); 
}

In C++0x, this gets even simpler (and typename is not needed):

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(); 
}

Among other advantages, std::begin and std::end work for raw arrays.

拒绝两难 2024-11-02 23:50:07

按照 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;

ADDED:
然后,您可以按如下方式使用该函数:

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;但如果您确实需要它,该标准保证为 DIY 解决方案提供足够的支持。请在此处查看更多信息:std::queue iteration

Following STL practice, I would recommend using two iterators for input parameters, instead of a container (for obvious reason of being able to work with only a part of a container, and generally with any sequence defined by iterators):

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();
}

In case you need the type of contained objects, use

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

ADDED:
You then can use the function as follows:

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;

Note that you cannot iterate over std::queue; but if you really need it, the standard guarantees enough support for a do-it-yourself solution. See more info here: std::queue iteration.

我一向站在原地 2024-11-02 23:50:07

如果仅对容器类型进行模板化,这是最简单的;值类型作为 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 会向您发出警告。

It's easiest if you templatize on the container type only; the value type is stored in all standard, Boost and Qt containers as the typedef member value_type. std::copy and ostream_iterator allow you to skip the lengthy iterator declarations.

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();
}

The typename is necessary to avoid ambiguity. Recent versions of GCC will warn you when you omit this keyword.

莫多说 2024-11-02 23:50:07

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

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

Use this. You need the typename part in order to tell the compiler that it should consider T::const_iterator a type while parsing, it can't really know that this is true until you actually call the function passing some T that has a const_iterator member type.

template<typename T>
std::string convert2Str(T const& cont) 
{
    std::ostringstream sStream; 
    for (typename T::const_iterator it = cont.begin(); it != cont.end(); ++it) {
        sStream << *it << " "; 
    }
    return sStream.str(); 
}
临风闻羌笛 2024-11-02 23:50:07

我认为这应该有效:

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

I think this should work:

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(); 
}

Demo : http://ideone.com/9pUVV

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文