2017-09-11 82 views
1

我想從std::ifstream實現一些讀取功能。 它需要分開pod類型和其他類型。 (目前std::string如何正確設計和實現功能模板專業化?

template <typename T, typename = std::enable_if<std::is_pod<T>::value>::type> 
T read(std::ifstream& fin); 

template <> 
std::string read<std::string, void>(std::ifstream& fin); 

int main() 
{ 
    std::ifstream fin("test", std::ios::binary); 
    int x = read<int>(fin); 
    std::string str = read<std::string, void>(fin); 
} 

我想,當我調用讀爲std::string從模板參數去掉「void」。 我怎樣才能得到它?

在此先感謝。


更新(2017年9月14日)

我從EC++得到了提示,並試圖執行以下代碼。

template <bool B> 
    struct is_fundamental { 
     enum { value = B }; 
    }; 

    template <typename T> 
    static T doRead(std::ifstream& fin, is_fundamental<true>); 

    template <typename T> 
    static T doRead(std::ifstream& fin, is_fundamental<false>); 

    template <> 
    static std::string doRead<std::string>(std::ifstream& fin, is_fundamental<false>); 

    template <typename T> 
    static T read(std::ifstream& fin) { 
     return doRead<T>(fin, is_fundamental<std::is_fundamental<T>::value>()); 
    } 


    int main() 
    { 
     std::string filename("./test.dat"); 
     std::ifstream fin(filename, std::ios::binary); 

     read<int>(fin); 
     read<std::string>(fin); 
     read<std::vector<int>>(fin); 

     return 0; 
    } 

爲每次讀取調用<>獲得正確的功能!

回答

3

問題是不可能部分專門化一個函數。

結構的使用怎麼樣?

如果你寫read廣告如下,

template <typename T> 
struct read 
{ 
    template <typename U = T> 
    typename std::enable_if<std::is_same<U, T>::value 
         && std::is_pod<T>::value, T>::type 
     operator() (std::ifstream & fin) 
    { /* do something; return a T */ } 
}; 

template <> 
struct read<std::string> 
{ 
    std::string operator() (std::ifstream & fin) 
    { /* do something; return a string */ } 
}; 

你有read結構,其中operator()只啓用了模板類型是POD,併爲std::string一個特殊版本的通用版本(和你可以加read的其他專業化;也可以部分專業化)。

的缺點是你必須改變的read()調用這樣

int x = read<int>{}(fin); 
std::string str = read<std::string>{}(fin); 

即,定義對象(read<T>{})。

如果你喜歡使用一個靜態成員裏讀 - 舉例,func() - 你能避免對象創建的需要,但你必須調用它以這種方式

int x = read<int>::func(fin); 
std::string str = read<std::string>::func(fin); 

以下是全工作示例

#include <vector> 
#include <fstream> 
#include <iostream> 
#include <type_traits> 

template <typename T> 
struct read 
{ 
    template <typename U = T> 
    typename std::enable_if<std::is_same<U, T>::value 
         && std::is_pod<T>::value, T>::type 
     operator() (std::ifstream & fin) 
    { T ret ; std::cout << "POD!" << std::endl ; fin >> ret ; return ret; } 
}; 

template <> 
struct read<std::string> 
{ 
    std::string operator() (std::ifstream & fin) 
    { std::string ret ; std::cout << "string!" << std::endl; fin >> ret ; 
     return ret; } 
}; 

int main() 
{ 
    std::ifstream fin("test", std::ios::binary); 
    int x = read<int>{}(fin);     // write POD! 
    std::string str = read<std::string>{}(fin); // write string! 
    //auto read<std::vector<int>>{}(fin);  // compilation error 
} 
+0

謝謝你的答案 – TwisTeDStRiDeR

+0

@TwisTeDStRiDeR如果答案幫助了你,請考慮接受它。 – whoan

+1

*「缺點是你必須以這種方式改變read()的調用」*。您可以繞過間接級別的缺點: 'template T read(std :: ifstream&fin){return my_read {}(fin); }(用正確的重命名)。 – Jarod42

1

作爲替代方案,可以使用過載和標籤調度:

template <typename> struct Tag {}; 

template <typename T, std::enable_if_t<std::is_pod<T>::value>* = nullptr> 
T read(Tag<T>, std::ifstream& fin); 

std::string read(Tag<std::string>, std::ifstream& fin); 

並使用它:

int main() 
{ 
    std::ifstream fin("test", std::ios::binary); 
    int x = read(Tag<int>{}, fin);    // write POD! 
    auto str = read(Tag<std::string>{}, fin); // write string! 
    //auto v = read(Tag<std::vector<int>>{}, fin); // compilation error 
}