基于整体 class 模板专门化 class 方法

Specializing a class method based on overall class template

我如何专门化 initialize()(见下文),其中类型不是基于方法参数,而是整个 class 模板参数?

template<class STREAM_TYPE>
class MyClass
{
    struct MyStruct
    {
        STREAM_TYPE* _ifs{nullptr};
    }

public:   

    // Use this when STREAM_TYPE = std::ifstream
    void initialize()
    {
        for(MyStruct& ms : _myStructs)
        {
            ms._ifs = new std::ifstream("");
        }
    }

    // Use this when STREAM_TYPE = std::stringstream
    void initialize()
    {
    }

private:
    std::array<MyStruct, 10> _myStructs;
};

class模板的非模板成员本身就是独立的模板。您可以独立地专门化它们。在你的情况下 - 通过使用显式专业化

// Main template
template<class STREAM_TYPE>
class MyClass
{
    void initialize()
    {
    }
};

// Specialization, declared outside the main template definition
template<>
void MyClass<std::ifstream>::initialize()
{
    for(MyStruct& ms : _myStructs)
    {
        ms._ifs = new std::ifstream("");
    }
}

哪个版本的方法是"default"版,哪个是"specialized"版,由你决定。或者您可能想将两个版本都声明为专业化。

例如,您可能决定将两个版本都视为专业化版本,同时将主要版本定义为已删除

// Main template
template<class STREAM_TYPE>
class MyClass
{
    void initialize() = delete;
};

// Specialization, declared outside the main template definition
template<>
void MyClass<std::ifstream>::initialize()
{
    for(MyStruct& ms : _myStructs)
    {
        ms._ifs = new std::ifstream("");
    }
}

template<>
void MyClass<std::stringstream>::initialize()
{
}

请记住,显式特化不再是模板。它作为普通函数服从 ODR。即使您的模板 class 是在头文件中定义的(通常是模板 class),上述专业化的定义也必须转到 .cpp 文件中。头文件应仅包含 声明 用于您的专业

// header file declarations
template<> void MyClass<std::ifstream>::initialize();
template<> void MyClass<std::stringstream>::initialize();

而定义应该转到 .cpp 文件。

如果使用 SFINAE 只启用正确的版本呢?

  template <typename ST = STREAM_TYPE>
  std::enable_if_t<std::is_same<ST, std::ifstream>::value> initialize ()
   {
     std::cout << "ifstream case" << std::endl;

     for (MyStruct & ms : _myStructs)
        ms._ifs = new std::ifstream("");
   }

  template <typename ST = STREAM_TYPE>
  std::enable_if_t<std::is_same<ST, std::stringstream>::value> initialize ()
   {
     std::cout << "stringstream case" << std::endl;
   }