ฉันจะใช้ CRTP ใน C ++ เพื่อหลีกเลี่ยงค่าใช้จ่ายของฟังก์ชันสมาชิกเสมือนได้อย่างไร
ฉันจะใช้ CRTP ใน C ++ เพื่อหลีกเลี่ยงค่าใช้จ่ายของฟังก์ชันสมาชิกเสมือนได้อย่างไร
คำตอบ:
มีสองวิธี
สิ่งแรกคือการระบุอินเทอร์เฟซแบบคงที่สำหรับโครงสร้างประเภท:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo(); // required to compile.
};
struct your_type : base<your_type> {
void foo(); // required to compile.
};
ประการที่สองคือการหลีกเลี่ยงการใช้สำนวนอ้างอิงถึงฐานหรือตัวชี้ไปที่ฐานและทำการเดินสายตามเวลาคอมไพล์ เมื่อใช้คำจำกัดความข้างต้นคุณสามารถมีฟังก์ชันเทมเพลตที่มีลักษณะดังนี้:
template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
obj.foo(); // will do static dispatch
}
struct not_derived_from_base { }; // notice, not derived from base
// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload
ดังนั้นการรวมนิยามโครงสร้าง / อินเทอร์เฟซและการหักประเภทเวลาคอมไพล์ในฟังก์ชันของคุณช่วยให้คุณทำการจัดส่งแบบคงที่แทนการจัดส่งแบบไดนามิก นี่คือสาระสำคัญของความหลากหลายแบบคงที่
template<class T> bar(base2<T> &obj) { obj.quux(); }
- คือคลาสฐานที่สองด้วยการbar()
ใช้งานที่แตกต่างกันและยูทิลิตี้ของ CRTP จะปรากฏ
ฉันกำลังมองหาการสนทนาที่ดีเกี่ยวกับ CRTP ด้วยตัวเอง เทคนิคของ Todd Veldhuizen สำหรับ Scientific C ++เป็นแหล่งข้อมูลที่ยอดเยี่ยมสำหรับสิ่งนี้ (1.3) และเทคนิคขั้นสูงอื่น ๆ อีกมากมายเช่นเทมเพลตนิพจน์
นอกจากนี้ฉันพบว่าคุณสามารถอ่านบทความ C ++ Gems ดั้งเดิมของ Coplien ได้ที่ Google หนังสือ อาจจะยังคงเป็นเช่นนั้น
dynamic_cast
หรือวิธีการเสมือน
ผมมองขึ้นCRTP มีการกระทำที่ แต่ผมพบว่าสิ่งบางอย่างเกี่ยวกับการคงความแตกต่าง ฉันสงสัยว่านี่คือคำตอบสำหรับคำถามของคุณ
ปรากฎว่าATLใช้รูปแบบนี้อย่างกว้างขวาง
คำตอบ Wikipedia นี้มีทุกอย่างที่คุณต้องการ ได้แก่ :
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
แม้ว่าฉันไม่รู้ว่าสิ่งนี้ซื้อคุณได้มากแค่ไหน ค่าใช้จ่ายของการเรียกฟังก์ชันเสมือนคือ (แน่นอนขึ้นอยู่กับคอมไพเลอร์):
ในขณะที่ค่าโสหุ้ยของความแตกต่างแบบคงที่ของ CRTP คือ:
not_derived_from_base
ว่าไม่ได้มาจากbase
และไม่ได้มาจากbase
...