专门用于方法c ++的类模板

时间:2013-04-16 19:08:21

标签: c++ templates

假设我有一个类模板,其中某些方法是特定于类型的。

template <typename T>
class Shape
{
...
void Foo();
...
};

现在我将专门使用类型特定的函数,例如:

void Shape<bool>::Foo() {...};
void Shape<double>::Foo() {...};

问题:

  1. 如果Foo根据类型应该有不同的参数怎么办?是否可以使用与类声明中的参数不同的参数来专门化特定类型的方法?我怀疑这是不允许的,所以应该怎么做?

  2. 如何防止未定义Foo的类型的类实例化?

  3. 应该使用虚拟和纯虚函数,而不是我所描述的语法?是否可以混合使用模板和继承?

2 个答案:

答案 0 :(得分:1)

  
      
  • 1a。如果Foo根据类型应该有不同的参数怎么办?是否可以使用与类声明中的参数不同的参数来专门化特定类型的方法?
  •   

No。是的,正如下面的Nathan Monteleone所指出的,这可以通过完全专门化类Shape来实现。

  
      
  • 1b。我怀疑这是不允许的,所以应该怎么做?
  •   

您可以将函数本身转换为独立于类

的模板
class Shape {
    //...
    template <typename T>
    void Foo();
    //...
};
  
      
  • 2。如何防止未定义Foo的类型的类实例化?
  •   

在课堂上:

template<typename U> //note the different typename
class Shape {
    static_assert(std::is_same<U, bool>::value || std::is_same<U, double>::value, "Type forbidden");
    //...
    inline void Foo() {
        if( std::is_same<U, bool>::value ) Foo_impl_bool();
        else if( std::is_same<U, double>::value ) Foo_impl_double();// and so on.
        // this function is likely to get optimized since the conditionals are constexpr
    }
    private:
    void Foo_impl_bool();//...
};
  

3a。什么时候应该使用虚拟和纯虚函数与我描述的情况形成对比?

1b和2的答案是两个独立的解决方案,如果它们都不可能,其他可能性是:

  1. 将该功能提取到自己的类中。

  2. 仅对此功能
  3. Use interface inheritance

  4.   

    3b。是否可以混合使用模板和继承?

答案 1 :(得分:0)

(1)排序,但不完全是你尝试的方式。你基本上想要专业化来定义函数;它与你声明基类和派生类时有很大的不同。

template <typename T> class Shape {
    static_assert(false, "Not implemented");
};

template <> class Shape<bool> {
    void Foo(bool a, std::string b) {...}
};

template <> class Shape<int> {
    void Foo(int, std::string, whatever else) {...}
};

即使你要在原始的非专业形状中定义Foo,它也不会影响专业化。完全专业化不会扩展原始模板,而是替换它!

(2)使用static_assert。请参阅上面的示例。

(3)是的,你可以混合模板和继承。虚函数运行时多态性和静态多态性。模板参数必须在编译时知道,而运行时多态对象的确切类型则不知道,因为它们可以由基类引用引用。在上面的模板示例中,您不能简单地说

template <class T> Shape {...};

...

Shape* myShape;   // Compiler error: Shape requires a template parameter

但是,如果有继承权,你可以:

class ShapeBase { virtual void Foo() = 0; };
class Circle : public ShapeBase { virtual void Foo() { ... } };
class Square : public ShapeBase { virtual void Foo() { ... } };
...

Shape* myShape = new Circle;
myShape->Foo(); // calls Circle->Foo()

注意当你使用继承时,函数签名必须匹配!这是你将决定推迟到运行时所付出的代价。