我是模板編程的新手,偶然發現了這個習慣用語。例如,類似于:
class FooBase {
public:
virtual void do_something()= 0;
};
template <class Foo> // Foo是來自FooBase。
void g(Foo& foo) {
static_assert(std::is_base_of<FooBase, Foo> ::value)。
// ...
foo.do_something()。
/ ... foo.do_something(;)
在我自己看來,這種模式是有用的,因為:
requires子句(如果有的話)相比,它很容易指定屬性、引數和回傳型別。FooBase頭,就可以清楚地了解定義一個新的Foo類的要求。FooBase類中。然而,我擔心使用虛擬函式的性能影響。我的理解是在運行時沒有成本,因為該函式是從派生類中呼叫的;但是聯結器將無法行內該函式。
另一個缺點是,虛擬模板函式是不允許的。
最后,我擔心這可能是一種普遍的代碼氣味,因為它使用了運行時多型性的功能來執行靜態檢查。C 20的概念可能是做到這一點的 "正確 "方法,但由于上述三個原因,它們似乎不太方便。
uj5u.com熱心網友回復:
這是個糟糕的做法,因為你使用了錯誤的工具。你正在撰寫傳達錯誤資訊的代碼,并且沒有實際的執行機制。
動態多型性的意義在于它是動態的:在運行時定義,這樣你就可以將物件傳遞給那些在編譯時并不完全知道它們的型別的函式。這允許在一個地方的代碼是針對基類寫的,而不是被匯出到頭檔案之類的地方。而在任何時候被使用的實際類也可以不被匯出到頭檔案之類的地方。只有該類的源頭需要知道實際的型別。
像模板這樣的編譯時多型性的前提是在編譯時了解一切。所有的代碼,包括源代碼和目標代碼,都需要知道型別是什么。
實質上,與編譯時多型性相比,你喜歡動態多型性闡述其要求的方式,但你試圖通過使用編譯時多型性來回避其性能成本。這就造成了代碼的混亂,因為你混淆了機制。
如果有人看到一個帶有虛擬函式的基類,他們會認為你的代碼會將指標/參考傳遞給周圍的實際類。這是在大多數情況下使用它們的期望的一部分(即使是基于virtual的型別清除也是如此)。相反,看到一堆按值獲取型別的模板函式會讓人感到困惑。
此外,你沒有執行機制。一個接受 FooBase& 的函式可以確保用戶不能用一個不是實際的 FooBase 派生型別的型別來呼叫它(好吧,你可以讓它隱含地轉換為一個型別,但是讓我們在這里忽略了敷衍)。你的模板函式,避開了概念,沒有類似的強制力。你可以記錄它必須是一個 FooBase 派生型別,但是你并沒有靜態地強制執行它。
至少,模板引數應該被宣告為std::derived_from<FooBase> Foo(而且,static_assert不是一個好主意)。
但實際上,你應該只使用一個適當的概念。你想要的是編譯時多型性,無論你對概念的個人感受是什么,概念都是C 20為編譯時多型性定義原型的語言機制。如果你使用概念,沒有人會對你的代碼的含義和意圖感到困惑。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/315767.html
標籤:
