سؤال

من المحتمل أن يكون هذا سؤالًا شديدًا جدًا بالنسبة لك: كيف (إذا كان ذلك ممكنًا) ، يمكنني إرجاع ifstream من وظيفة؟

في الأساس ، أحتاج إلى الحصول على اسم ملف قاعدة بيانات من المستخدم ، وإذا لم تكن قاعدة البيانات مع اسم الملف موجودًا ، فأنا بحاجة إلى إنشاء هذا الملف للمستخدم. أعرف كيفية القيام بذلك ، ولكن فقط عن طريق مطالبة المستخدم بإعادة تشغيل البرنامج بعد إنشاء الملف. أردت تجنب هذا الإزعاج للمستخدم إن أمكن ، لكن الوظيفة أدناه لا تتجمع في مجلس التعاون الخليجي:

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 

تحرير: لقد قمت بتغيير الوظيفة لإرجاع مؤشر بدلاً من ذلك كما اقترح Remus ، وقمت بتغيير الخط في Main () إلى "Ifstream Database = *getFile ()" ؛ الآن أحصل على هذا الخطأ مرة أخرى ، ولكن هذه المرة في السطر في Main ():

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) الحصول على اسم ملف ، 2) افتح أو إنشاء هذا الملف. أعتقد أنه إذا قمت بفصلها ، فسيكون الرمز أكثر بساطة ، ويجعل من الأسهل القضاء على مصدر المشكلة التي تراها.

تحرير 2: استخدام مرجع مثل هذا يعمل بشكل جيد تمامًا بدون operator=. الفكرة العامة هي شيء مثل:

int open_file(char const *name, fstream &stream) { 
    stream.open(name);
}

مشغل الواجب ليس ضروريًا ولا مفيدًا في هذه الحالة - نحن ببساطة نستخدم FSTream الموجود عبر المرجع. و operator= سيكون ضروريًا إذا وفقط إذا كان علينا نقل الحجة إلى CTOR. باستخدام دفق ، يمكننا إنشاء دفق لا يتصل بملف ، ثم استخدم Open للاتصال بالملف بعد الحقيقة.

لا يدعم Ifstream دلالات بنية النسخ (أن رسالة الخطأ بشكل أساسي SAIS) ، لذلك لا يمكنك إرجاع 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());
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top