代码之家  ›  专栏  ›  技术社区  ›  tjwrona1992

成员变量如何与专用类模板一起工作?

  •  1
  • tjwrona1992  · 技术社区  · 5 年前

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

    当专门化类模板时,类的专门化似乎不共享相同的成员变量,因此以下代码将不会编译。。。

    #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 如果我有很多专业化的话,每一个专业化都会很快变成很多重复的代码和工作。

    如果我说的是真的,那么在专门的类模板中一起使用成员变量是不是不好?有没有其他方法可以减少代码重复?

    3 回复  |  直到 5 年前
        1
  •  3
  •   n314159    5 年前

    你是对的,专业化基本上完全独立于彼此和原始模板,所以你必须写所有新的东西。解决这个问题的一个方法是使用继承。

    #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
  •  2
  •   David G    5 年前

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

    template <>
    void S<std::string>::print()
    {
        std::cout << "string: " << t << std::endl;
    }
    
        3
  •  1
  •   max66    5 年前

    另一种可能的解决方案是标签显示

    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>{}); }
     };