【问题标题】:How do member variables work with specialized class templates?成员变量如何与专门的类模板一起工作?
【发布时间】:2019-12-27 18:15:19
【问题描述】:

我正在尝试编写一个非常简单的专用类模板,它有一个成员变量,并且可以在特殊情况下以不同的方式打印该成员变量。我知道这个例子没什么用,但它很好地说明了这个问题。

当特化类模板时,似乎类的特化不共享相同的成员变量,所以下面的代码不会编译...

#include <iostream>
#include <string>

// Class template
template <typename T>
struct S
{
    S(const T& t)
        : t(t)
    {}

    void print()
    {
        std::cout << t << std::endl;
    }
private:
    T t;
};

// Specialization
template <>
struct S<std::string>
{
    void print()
    {
        // ERROR: "t" is not defined in this context
        std::cout << "string: " << t << std::endl;
    }
};

这表明我需要为每个专业化编写一个单独的构造函数,并为每个专业化有一个单独的成员变量t,如果我有很多专业化,这感觉很快就会变成大量重复的代码和工作。

如果我说的是真的,那么在专门的类模板中完全使用成员变量是不好的做法吗?是否有任何替代方案可以减少代码重复?

【问题讨论】:

    标签: c++ templates template-specialization member-variables


    【解决方案1】:

    还请看@0x499602D2 的回答,它更简单,适用于许多实际案例。

    您是对的,专业化基本上完全独立于彼此和原始模板,因此您必须编写所有新内容。一种解决方法是使用继承。

    #include <iostream>
    #include <string>
    
    // Class template
    template <typename T>
    struct Base
    {
        Base(const T& t)
            : t(t)
        {}
    
        virtual void print()
        {
            std::cout << t << std::endl;
        }
    
    protected:
        T t;
    };
    
    template<class T>
    struct S: Base<T> {
    };
    
    // Specialization
    template <>
    struct S<std::string>: Base<std::string>
    {
        void print() override
        {
            std::cout << "string: " << t << std::endl;
        }
    };
    

    【讨论】:

      【解决方案2】:

      由于您只特化单个模板参数,您可以显式特化成员函数而不是整个类:

      template <>
      void S<std::string>::print()
      {
          std::cout << "string: " << t << std::endl;
      }
      

      【讨论】:

      • 哦,太好了!我从来没想过这点。不过,这不适用于部分专业化,对吧?
      • @tjwrona1992 不,它只适用于明确的专业化。
      【解决方案3】:

      另一种可能的解决方案是标签调度

      template <typename T>
      struct S
       {
         private:
            T t;
      
            void print_helper (std::true_type) // T is std::string
             { std::cout << "string: " << t << std::endl; }
      
            void print_helper (std::false_type) // T isn't std::string
             { std::cout << t << std::endl; }
      
         public:
            S (T const & t0) : t{t0}
             { } 
      
            void print ()
             { print_helper(std::is_same<T, std::string>{}); }
       };
      

      【讨论】:

        【解决方案4】:

        另一种方法是使用辅助函数。这将让您进行部分模板专业化,解决@0x499602D2 指出的问题。我们正在做的是让模板化函数调用一个辅助函数,而这个辅助函数正在做所有的特化。

        我在其中添加了另一个模板参数,以表明这种解决方案适用于部分模板专业化。请注意,模板化的辅助函数是完全专用的,而不是部分专用的。你不能部分专门化一个函数。这在类模板具有更多您无法专门化的模板参数 (UNUSED_T) 但您确实想要专门化可以的函数的情况下很有用完全专业化(print_it 不需要 UNUSED_T)。

        #include <iostream>
        #include <string>
        
        // This is the helper function for all types T...
        template <typename T>
        void print_it(T t) {
            std::cout << t << std::endl;
        }
        
        // ... except for std::string, it will run this one.
        template <>
        void print_it<std::string>(std::string t) {
            std::cout << "string: " << t << std::endl;
        }
        
        // Class template, UNUSED is there just to show that
        // this works for partial template specialization.
        template <typename T, typename UNUSED_T>
        struct S {
            S(const T& t) : t(t) {}
        
            void print() {
                // You can remove the <T> because
                // the compiler will figure it out for you.
                print_it<T>(t);
            }
        prviate:
            T t;
            UNUSED_T unused;
        };
        
        int main() {
            S<uint, char> x(5);
            x.print(); // OUTPUT: 5
            S<std::string, char> y("foo");
            y.print(); // OUTPUT: string: foo
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-02-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多