我认为你的主要问题是
ofstream
和
ostream_iterator
不能默认构造(构造时没有参数)或分配,因此不能使用Cython中分配的堆栈(即,需要使用
new
).
我构建了一个非常简单的示例来演示如何做到这一点。我试图通过忽略不必要的模板参数(默认值正确的地方)并只包含实际使用的函数,尽可能简化C++声明。
我已经分配了
文件输出流
作为指针
新
以及
ostream\u迭代器
作为一个临时的我直接进入
copy
. 还可以分配
ostream\u迭代器
作为指针,尽管这似乎没有必要。
#distutils: language=c++
from libcpp.vector cimport vector
cdef extern from "<ostream>" namespace "std":
cdef cppclass ostream:
ostream& put(char c) # just to write the newlines
cdef extern from "<istream>" namespace "sts":
cdef cppclass istream:
pass
cdef extern from "<fstream>" namespace "std":
cdef cppclass ofstream(ostream):
ofstream(const char*)
cdef cppclass ifstream(istream):
ifstream(const char*)
cdef extern from "<iterator>" namespace "std":
cdef cppclass ostream_iterator[T]:
ostream_iterator(ostream&, const char*)
cdef cppclass istream_iterator[T]:
istream_iterator(istream&)
istream_iterator()
cdef extern from "<algorithm>" namespace "std":
OutputIterator copy[InputIterator,OutputIterator](InputIterator, InputIterator, OutputIterator)
def test_func_write(l):
"Takes a list/tuple, converts it to a vector
and then prints that twice"
cdef vector[int] v = l
cdef ofstream* fout = new ofstream("output.txt");
try:
copy(v.begin(),v.end(),ostream_iterator[int](fout[0]," "))
fout.put("\n")
copy(v.begin(),v.end(),ostream_iterator[int](fout[0]," "))
fout.put("\n")
finally:
del fout
def test_func_read():
cdef vector[int] v
cdef ifstream* fin = new ifstream("output.txt")
try:
v.insert(v.end(),istream_iterator[int](fin[0]),istream_iterator[int]())
return v
finally:
del fin
我直接给
fout
使用
put
作用
阅读总是比写作复杂一点。我们可以
insert
直接输入向量,它会一直读到最后。不幸的是,它对换行符和空格的处理是相同的(这在C++流中很难更改),因此很难在执行时计算出矩阵的形状。最简单的解决方案是编写文件,以便第一个元素给出列数。更复杂的方法是使用
getline
将每一行作为字符串,然后
istringstream
对于每一行。
控制格式
真的不起作用
对于
ostream\u迭代器
. 这个
ostream
具有多种功能来控制格式(例如。
width
,
fill
和
setf
. 但是,它们仅适用于下一个输出,然后被重置。因此,迭代器编写多个输出时,它们是非常无用的。通用解决方案(
1
2
)似乎是编写一个包装器类来应用于每个元素的格式化程序,但这在Cython中并不实际。
以防您想使用格式标志(并一次写入一个元素),您可以这样做
cdef extern from "<ostream>" namespace "std":
cdef cppclass fmtflags "std::ios_base::fmtflags":
pass
fmtflags left "std::ios_base::left"
fmtflags right "std::ios_base::left"
# etc...
cdef cppclass ostream:
#...
fmtflags setf(fmtflags)
int width(int)
char fill(char)
然后你只要打电话:
fout.width(10)
fout.fill("x")
fout.setf(left)
无论如何,我真的不认为尝试在Cython中使用C++标准库编写matrix类是一个好主意,因为Cython对C++模板的支持有限。
希望最终编辑:
您的“阅读”示例使用
getline公司
和
istringstream公司
就在不远的地方。只是列出我必须做的更改
# istream needs a "bool" operator for you to use it in a while loop.
# You could also use the function "good()"
from libcpp cimport bool
cdef extern from "<istream>" namespace "std":
cdef cppclass istream:
bool operator bool()
# You need to declare getline. I'm using the simpler version without
# the delimiter but it doesn't really matter
cdef extern from "<string>" namespace "std":
istream& getline(istream&, string& s)
# the loop looks like:
while (getline(infile[0], line)):
self.matrix.insert(self.matrix.end(), # use "end" to insert at the back (this was a mistake in my original example
istream_iterator[double](istringstream(line)), # just make the istringstream as a temporary
istream_iterator[double]())
if (i==0):
columns= self.matrix.size()
i += 1 # you forgot this