機能にはifstreamを返します
質問
ここでは、おそらくあなたのために非常にnoobish質問です:?どのように(すべての可能であれば)私は関数からはifstreamを返すことができます。
基本的に、私は、ユーザーからのデータベースのファイル名を取得する必要があり、そのファイル名を持つデータベースが存在しない場合は、その後、私は、ユーザーのためにそのファイルを作成する必要があります。私はそれを行う方法を知っているが、専用のファイルを作成した後、プログラムを再起動するようにユーザーに尋ねることもできます。私は、可能な場合には、ユーザーのためにその不便さを避けたかったが、以下の機能は、GCCでコンパイルされません。
ifstream getFile() {
string fileName;
cout << "Please enter in the name of the file you'd like to open: ";
cin >> fileName;
ifstream first(fileName.c_str());
if(first.fail()) {
cout << "File " << fileName << " not found.\n";
first.close();
ofstream second(fileName.c_str());
cout << "File created.\n";
second.close();
ifstream third(fileName.c_str());
return third; //compiler error here
}
else
return first;
}
編集:申し訳ありませんが、どこで、どのようなコンパイラエラーだったあなたを伝えるのを忘れます:
main.cpp:45: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here
編集:私はレムスが示唆されているように代わりにポインタを返すように関数を変更し、(主にラインを変更)「はifstreamデータベース= *はgetFile()」に、今私は再びこのエラーを取得しますが、()メインの行で、この時点ます:
main.cpp:27: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here
解決
bool checkFileExistence(const string& filename)
{
ifstream f(filename.c_str());
return f.is_open();
}
string getFileName()
{
string filename;
cout << "Please enter in the name of the file you'd like to open: ";
cin >> filename;
return filename;
}
void getFile(string filename, /*out*/ ifstream& file)
{
const bool file_exists = checkFileExistence(filename);
if (!file_exists) {
cout << "File " << filename << " not found." << endl;
filename = getFileName(); // poor style to reset input parameter though
ofstream dummy(filename.c_str();
if (!dummy.is_open()) {
cerr << "Could not create file." << endl;
return;
}
cout << "File created." << endl;
}
file.open(filename.c_str());
}
int main()
{
// ...
ifstream file;
getFile("filename.ext", file);
if (file.is_open()) {
// do any stuff with file
}
// ...
}
他のヒント
いや、そうでもありません。手段はリターンが行く必要がどこに出て、あなたの関数でインスタンスをコピーすること、ifstream
は、コピーコンストラクタを持っていない、とあなたは1を返すようにしよう。
通常の回避策は、1への参照を渡すと、あなたの関数で、その参照を変更することです。
編集:それは仕事にあなたのコードを許可する一方で、それは基本的な問題を解決しません。 1)ファイル名、2)オープンを取得したり、そのファイルを作成します。今、あなたは、単一の関数に2つのかなり異なる責任を混合しています。私はあなたがそれらを分離した場合、コードはシンプルに、そして、それははるかに簡単にあなたがしているシーイング問題の原因を除去するために行うことになると思います。
編集2:このような参照を使用すると、operator=
せずに完璧に適しています。一般的な考え方は次のようにあります:
int open_file(char const *name, fstream &stream) {
stream.open(name);
}
代入演算子は、この場合に必要でも有益でもない - 私たちは、単に参照を経由して、既存のfstreamを使用します。 operator=
は、私たちがctorのに引数を渡すために持っていた場合にのみの場合の必要があろう。ストリームでは、我々はファイルに接続し、事実の後にファイルに接続するために開いて使用していないストリームを構築するデフォルトすることができます。
はifstreamは(どのようなエラーメッセージは、基本的サイスこと)、あなたははifstreamを返すことができませんので、コピーコンストラクトセマンティクスをサポートしていません。代わりに、*はifstreamを返し、呼び出し元へのポインタを割り当てる削除するの責任を渡します。
このコメントは、私はちょうど彼の答えについて氏@Corwinをお願いしたいと思います、あなたの質問に答えられないことがあります。
ただ、彼のコードのように、私たちは持っている:ファイル名を要求するためのgetFileName
ブロックを、私は(これは私の意見です)私たちは、このようなコードべきだと思います:
void getFile(/*out*/ ifstream& file){
string filename = getFileName();
const bool file_exist = checkFileExistence(filename);
if (!file_exist){
....
}
....
}
そしてint main()
で、私が思うにます:
int main(){
ifstream file;
getFile(file);
if (file.is_open()){
//some stuff
}
}
これにより、コンソールでユーザーの入力からfilename
を取得することができます。
の方法では、その助けに私のコードのために多くのことを氏@Corwinに感謝します。
オプションとして、はifstreamを延長することができるとカスタムコンストラクタは、新しいクラスに追加します。
私はそれのテストリソースのルックアップの内部をカプセル化し、テストリソースストリームを作成するためにそれを拡張しました。
// test_utils.h
class TestResourceStream : public std::ifstream {
public:
TestResourceStream(const char* file_path);
};
// test_utils.cpp
namespace fs = std::filesystem;
fs::path test_resource_path(const char* file_path) {
fs::path path{std::string{"tests/resources/"} + file_path};
if (!fs::exists(path))
throw std::runtime_error{std::string{"path "} +
fs::absolute(path).c_str() + " does not exist"};
return path;
}
TestResourceStream::TestResourceStream(const char* file_path)
:std::ifstream{test_resource_path(file_path).c_str()} {}
// usage in test
TEST_CASE("parse") {
std::list<GosDump::Expertise> expertises;
TestResourceStream stream("requests/page_response.json");
GosDump::Json::parse(expertises, stream);
REQUIRE(10 == expertises.size());
}