簡體   English   中英

專門用於方法C的類模板

[英]Class template specializing a method c++

說我有一個類模板,其中某些方法是特定於類型的。

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

現在,我將使用例如特定於類型的函數:

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

題:

  1. 如果Foo根據類型具有不同的參數怎么辦? 是否可以使用與類聲明中的參數不同的參數來為特定類型的方法專門化? 我懷疑這是不允許的,那么應該怎么做?

  2. 如何防止未定義Foo的類型的類實例化?

  3. 與我描述的方法相比,什么時候應該使用虛函數和純虛函數? 是否可以將模板和繼承混在一起?

  • 1a。 如果Foo根據類型具有不同的參數怎么辦? 是否可以使用與類聲明中的參數不同的參數來為特定類型的方法專門化?

不, 是的,正如下面的內森·蒙特萊昂(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的答案是2個單獨的解決方案,如果它們都不可行,則其他可能性是:

  1. 將該函數提取到其自己的類中。

  2. 僅將接口繼承用於此功能。

3b。 是否可以將模板和繼承混在一起?

(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()

注意,在使用繼承時,功能簽名必須匹配! 這就是您將決策推遲到運行時所要付出的代價。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM