2016-12-01 56 views
0

我正在和一位同事討論,我認爲這將是一個很好的問題放在這裏。文件或流的路徑?

當設計API時,你的函數應該接受文件路徑,什麼時候應該接受流?有沒有任何指導方針?

void do_something(const std::filesystem::path &file_path); 
void do_something(std::istream &stream); 

路徑:

  • 被叫負責檢查該文件存在並且可以訪問。
  • 很難進行單元測試。你必須在磁盤上創建/擁有一個文件來測試它。

流:

  • 來電者是負責檢查該文件存在並且可以訪問。更多重複的樣板代碼。
  • 單元測試更容易,你可以只通過一個流對象

我想一個可能的功能添加到庫中,以「幫助」打開文件時,各種各樣的東西:

std::ifstream open_input(const std::filesystem::path &file) 
{ 
    std::ifstream stream(file); 

    if (not stream) { 
     throw std::invalid_argument("failed to open file: " + file.string()); 
    } 

    return stream; 
} 
+0

我個人一直使用的路徑,因爲這樣我可以檢查的類型,如「.TXT」 –

+0

恐怕這個問題將被封閉,過於寬泛或基於觀點。儘管如此,我更喜歡第二個版本,因爲它更靈活(可以與其他流一起使用),並且服從SRP。事實上,我會考慮更進一步,並創建一個基於API迭代器的。 – user58697

+0

@ user58697處理文件時基於迭代器? – Mac

回答

0

你自己說過,你可以添加「助手」功能來保存istream接口。這在測試性方面也是更好的解決方案,並遵守單一責任原則(SRP)。

你的幫助函數有一個責任(從文件創建流)和另一個實際函數(它「做某事」:))。

我想補充一點,它取決於實際做的事情的背景。例如,如果它是一個facade用於對基礎功能的不同訪問,那麼將該接口與實際路徑相關聯是有意義的。你仍然會有一個獨立的幫助函數和一個do_something函數,這些函數從外觀中使用。

0

你可能有你的魚與熊掌兼得:

#include <fstream> 
#include <sstream> 
#include <utility> 

// 
// some booilerplate to allow use of a polymorphic temporary 
template<class Stream, std::enable_if_t<std::is_base_of<std::istream, Stream>::value> * = nullptr> 
struct stream_holder 
{ 
    stream_holder(Stream stream) : stream_(std::move(stream)) {} 
    operator std::istream&() && { return stream_; } 
    operator std::istream&() & { return stream_; } 

    private: 
    Stream stream_; 
}; 

// helper function 
template<class Stream, std::enable_if_t<std::is_base_of<std::istream, Stream>::value> * = nullptr> 
auto with_this(Stream&& stream) 
{ 
    return stream_holder<std::decay_t<Stream>>(std::forward<Stream>(stream)); 
} 



// express logic in terms of stream 
void do_something(std::istream& stream_ref); 

// utility functions to create various types of stream 
std::ifstream file_stream(); 
std::stringstream string_stream(); 


int main() 
{ 

    // * composability with succinct syntax 
    // * lifetime automatically managed 
    // * no repetitive boilerplate 
    do_something(with_this(file_stream())); 
    do_something(with_this(string_stream())); 
}