如何正确设计和实现功能模板专业化?

时间:2017-09-11 01:21:58

标签: c++ c++11 template-specialization sfinae typetraits

我想从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);
}

我想删除&#39; void&#39;我调用std::string的读取时从模板参数。 我怎么能得到它?

提前致谢。

更新(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;
    }

调用每次读取&lt;&gt;得到了正确的功能!

2 个答案:

答案 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
 }

答案 1 :(得分: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
}