我正在制作一个玩具程序来从字符串创建类(例如,我将它作为“test1 test2”提供它,它使test1.cpp,test1.h,test2.cpp,test2.h)
此功能发生在此功能中:
bool makeClassesFromString(std::string classNames){
bool returnValue = true;
if (classNames == ""){
returnValue = false;
}
else{
std::istringstream issClassNames (classNames);
std::string sClassName;
while(issClassNames.good()){
issClassNames >> sClassName;
std::string sourceName = sClassName;
sourceName += ".cpp";
std::string headerName = sClassName;
headerName += ".h";
std::ofstream source(sourceName.c_str()), std::ios::app);
std::ofstream header(headerName.c_str()), std::ios::app);
//source << "#include \"" << headerName << "\"";
source.close();
header.close();
}
}
return returnValue;
}
文件以追加模式打开,以确保不会意外覆盖任何已存在的类。
我最近回到这个程序包含一些额外内容 - 特别是旧版本只创建了两个空文件,我想修改它以创建具有必要定义和包含的文件,所以我不必手动去每次都添加它们。这显示出意想不到的行为 - 最后一个类要获得两次添加任何文本。
在上面的代码示例中,我已经注释掉了我开始处理这个问题的行,但是当我不对它进行评论时,我会得到这样的行为:
input:
classmaker.exe test1 test2
output:
test1.h
test2.h
test1.cpp //(Which contains: #include "test1.h")
test2.cpp //(Which contains: #include "test2.h"#include "test2.h"
我的猜测是我的while(issClassNames.good())
使用最后一个类名返回一个额外的时间(所以再次将该字符串附加到源文件中)但我不确定是什么行为驱动了这个。
到目前为止提出的解决方案:
ifstream
模式下打开之前,测试文件是否已存在,尝试以ofstream
模式打开。 (问题:无法解决一旦模式运行while
的问题)修改
我已经意识到:istringstream.good()并不是真的再次返回true,而是它的评估结果如下:
input: "test1 test2"
evaluation:
good = true; extract next to string //(succeeds, overwrites empty string with "test1")
good = true; extract next to string //(succeeds, overwrites "test1" with "test2")
good = true; extract next to string //(fails, Doesn't overwrite "test2")
good = false; break loop.
编辑2 + 3
那很容易解决。谢谢你们所有人。不幸的是,我只能将一个答案标记为已接受,所以我选择了第一个发布的答案,但我感谢您的帮助。
最终的整个计划:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
void makeClassesFromStdInput();
void makeClassesFromParameter(int argc, const char** argv);
bool makeClassesFromString(std::string classNames);
int main(int argc, const char** argv){
switch (argc) {
case 0: //This shouldn’t happen
break;
case 1:
//This will keep making classes from the CLI until
//the user breaks the process.
makeClassesFromStdInput();
break;
default:
//This will make classes from the parameters passed
//to the program except the first parameter which is
//assumed to be the program name.
makeClassesFromParameter(argc, argv);
break;
}
return 0;
}
void makeClassesFromStdInput(){
std::cout << "Input class name and press enter.\nWhitespace delimits class names.\nA blank line ends the process.\n>";
bool running = true;
std::string classNames;
while(running){
std::getline(std::cin, classNames);
running = makeClassesFromString(classNames);
}
}
void makeClassesFromParameter(int argc, const char** argv){
std::string classNames = "";
for(int i = 1; i<argc; i++){
classNames += argv[i];
classNames += " ";
}
makeClassesFromString(classNames);
}
bool makeClassesFromString(std::string classNames){
bool returnValue = true;
if (classNames == ""){
returnValue = false;
}
else{
std::istringstream issClassNames (classNames);
std::string sClassName;
while(issClassNames >> sClassName){
std::string sourceName = sClassName;
sourceName += ".cpp";
std::string headerName = sClassName;
headerName += ".h";
std::ofstream source(sourceName.c_str(), std::ios::app);
std::ofstream header(headerName.c_str(), std::ios::app);
source << "#include \"" << headerName << "\"";
//Header is slightly more involved because we want all capital letters
for (std::string::size_type i=0; i<headerName.length(); ++i){
if(headerName[i] == '.'){
headerName[i] = '_';
}
else{
headerName[i] = toupper(headerName[i]);
}
}
header << "#ifndef __" << headerName << "\n"
<< "#define __" << headerName << "\n"
<< "\n"
<< "\n"
<< "#endif";
source.close();
header.close();
}
}
return returnValue;
}
答案 0 :(得分:4)
流无法知道您要阅读的内容。您总是需要在之后检查,如果您的读取尝试成功,则尝试阅读
:while(issClassNames >> sClassName) {
// do whatever processing of sClassName you want to do
}
答案 1 :(得分:2)
你应该替换
while(issClassNames.good()){
issClassNames >> sClassName;
与
while(issClassNames >> sClassName) {
为什么
假设您的输入为test1 test2
。你先检查流是好的。由于没有错误,因此您可以阅读test1
中的sClassName
。现在流仍然很好,所以你继续阅读test2
中的sClassName
(此步骤中没有错误)。流仍然很好所以你继续尝试再次阅读,但operator >>
失败,sClassName
保持不变,因此你看到旧的值test2
。
operator >>
返回流本身的句柄(可转换为bool
),我们可以在条件中使用。所以只有在读取成功的情况下才会进入循环。
答案 2 :(得分:2)
尝试更改:
while(issClassNames.good()){
为:
while(issClassNames >> sClassName){
将该行从循环顶部取出。
流运算符>>
返回一个流,可以将其强制转换为bool,结果为good()
的结果。由于返回的流在调用>>
之后处于状态,如果操作设置了eof
位,它将返回false。