2017-09-11 87 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 
}