Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::string的非关联容器的io_C++_String_Templates - Fatal编程技术网

C++ std::string的非关联容器的io

C++ std::string的非关联容器的io,c++,string,templates,C++,String,Templates,我想为库中std::string的容器提供一个基于行的通用IO。 基于行,因为字符串可能包含空格。 下面的代码似乎工作得很好,但我不确定这是否是最好的方法,或者它是否会产生一些歧义,我无法理解 #define boostForeach BOOST_FOREACH template< template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container > std::ostr

我想为库中std::string的容器提供一个基于行的通用IO。 基于行,因为字符串可能包含空格。 下面的代码似乎工作得很好,但我不确定这是否是最好的方法,或者它是否会产生一些歧义,我无法理解

#define boostForeach BOOST_FOREACH

template< template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container >
std::ostream& operator<< (std::ostream& o, Container<std::string>const & container){
  boostForeach(std::string const& str, container) {
    o << str << "\n";
  }
  return o;
}

template< template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container >
std::istream& operator>> (std::istream& in, Container<std::string>& container){
  container.clear();
  std::string buf;
  while(getline(in, buf)) {
    if(buf.empty()) break; //stop if empty line found to separate map from other data
    container.insert(container.end(),buf);
  }
  return in;
}
#定义boostForeach BOOST\u FOREACH
模板<模板类容器>
std::ostream&operator(std::istream&in、容器和容器){
容器。清除();
std::字符串buf;
while(getline(in,buf)){
if(buf.empty())break;//如果发现将映射与其他数据分隔开的空行,则停止
container.insert(container.end(),buf);
}
返回;
}

所以问题是:这是否安全可靠?

第一个问题是标准容器中模板参数的数量不受标准的约束,这意味着您的代码在任何有额外参数的平台上都会失败

一般来说,我不会为尚未定义的类型提供运算符重载,尤其是对于标准容器。原因是你做不好。特别是,您不能在容器所在的名称空间中声明它们,这意味着ADL不会像魔术一样选择正确的重载。如果您想要一个helper函数,您应该提供一个命名函数,如果需要的话,在这里帮助查找会更简单

试试这个:

#include <iostream>
#include <vector>
#include <string>

template < template<typename,typename> class Container >
std::ostream& operator<<( std::ostream& o, Container<std::string> const & c );
namespace A {
   struct S {};
   std::ostream& operator<<( std::ostream& o, S const & );
   void f() {
      std::vector<std::string> v;
      std::cout << v;
   }
}
int main() {
   A::f();
}
#包括
#包括
#包括
模板<模板类容器>

std::ostream&operator第一个问题是标准容器中模板参数的数量不受标准的约束,这意味着您的代码在任何有额外参数的平台上都会失败

一般来说,我不会为尚未定义的类型提供运算符重载,尤其是对于标准容器。原因是你做不好。特别是,您不能在容器所在的名称空间中声明它们,这意味着ADL不会像魔术一样选择正确的重载。如果您想要一个helper函数,您应该提供一个命名函数,如果需要的话,在这里帮助查找会更简单

试试这个:

#include <iostream>
#include <vector>
#include <string>

template < template<typename,typename> class Container >
std::ostream& operator<<( std::ostream& o, Container<std::string> const & c );
namespace A {
   struct S {};
   std::ostream& operator<<( std::ostream& o, S const & );
   void f() {
      std::vector<std::string> v;
      std::cout << v;
   }
}
int main() {
   A::f();
}
#包括
#包括
#包括
模板<模板类容器>

std::ostream&operator您可以使用
std::copy()
编写输出算法:


将逻辑分离为迭代器类型可以使输入和输出算法参数化,从而更通用。在模板库中,这通常是一件好事。我会避免为标准容器添加重载,因为您无法知道它们在每个平台上都做了正确的事情;基于迭代器的算法更具可移植性,您不必编写所有的
模板
cruft.

您可以使用
std::copy()
编写输出算法:


将逻辑分离为迭代器类型可以使输入和输出算法参数化,从而更通用。在模板库中,这通常是一件好事。我会避免为标准容器添加重载,因为您无法知道它们在每个平台上都做了正确的事情;基于迭代器的算法更具可移植性,您不必编写所有的
模板
cruft.

您可能需要。:)@网络编码员:很好!我不知道这件事,一定会试试看你可能想试试。:)@网络编码员:很好!我不知道这一点,肯定会尝试一下,作为反例。你说得很对,我完全忽略了不同名称空间的含义play@Martin:我已看到您的编辑请求。因此,我修改了代码,使其适当地失败。请注意,不需要模板或函数定义,并且在Ideone上不需要模板参数的模板参数名称(默认值也不需要),因为您的代码没有结构,并且相应的运算符仍然失败:prog.cpp:6:错误:模板参数数目错误(1,应该是2)prog.cpp:5:错误:为“模板类容器”提供。std::vector的一个模板参数具有默认值。这就是为什么可能需要完整规范的原因。我添加了模板定义,以便在不存在结构的情况下运行代码。感谢反例。你说得对,我完全忽略了不同名称空间进入时的简化play@Martin:我已看到您的编辑请求。因此,我修改了代码,使其相应地失败。请注意,不需要模板或函数定义,并且模板模板参数的模板参数名称在事件中也不需要(默认值更小)在Ideone上,没有结构的代码和相应的运算符仍然失败:prog.cpp:6:错误:模板参数的数目错误(1,应该是2)prog.cpp:5:错误:为“模板类容器”提供。std::vector的一个模板参数具有默认值。这就是为什么可能需要完整规范的原因。我添加了模板定义,以便在结构不存在时运行代码。
class istream_paragraph_iterator: public std::iterator<std::forward_iterator_tag,std::string>{
    std::istream* stream;
    std::string line;
public:

    istream_paragraph_iterator() : stream(0) {}

    istream_paragraph_iterator(std::istream& stream) : stream(&stream) {++*this; //get the first element
    }

    std::string operator*() const {
        return line;
    }

    const std::string* operator->() const {
        return &line;
    }

    istream_paragraph_iterator& operator++() {
        if (stream && (!std::getline(*stream, line) || line.empty()))
            stream = 0;
        return *this;
    }

    istream_paragraph_iterator operator++(int) {
        istream_paragraph_iterator previous(*this);
        ++*this;
        return previous;
    }

    bool operator==(const istream_paragraph_iterator& other) const {
        return stream == other.stream;
    }

    bool operator!=(const istream_paragraph_iterator& other) const {
        return !(*this == other);
    }

};
std::copy(istream_paragraph_iterator(in),
    istream_paragraph_iterator(),
    std::back_inserter(container));