【问题标题】:How to design and implement function template specialization properly?如何正确设计和实现功能模板专业化?
【发布时间】:2017-09-11 01:21:57
【问题描述】:

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

为每次读取调用获得正确的功能!

【问题讨论】:

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


    【解决方案1】:

    问题是不可能对函数进行部分特化。

    结构体的使用怎么样?

    如果你写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 的专用版本(并且您可以添加@987654327 的其他专业化@; 也可以部分特化)。

    缺点是你必须这样改变read()的调用

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

    即定义一个对象(read&lt;T&gt;{})。

    如果您更喜欢在 read 中使用静态成员——例如,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
     }
    

    【讨论】:

    • 感谢您的回答
    • @TwisTeDStRiDeR 如果答案对您有帮助,请考虑接受。
    • “缺点是你必须以这种方式更改 read() 的调用”。您可以通过一定程度的间接绕过这个缺点:template &lt;typename T&gt; T read(std::ifstream &amp; fin) { return my_read&lt;T&gt;{}(fin); }(使用正确的重命名)。
    【解决方案2】:

    作为替代方案,您可以使用重载和标签调度:

    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
    }
    

    【讨论】:

      猜你喜欢
      • 2020-06-26
      • 1970-01-01
      • 2011-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多