ฟังก์ชั่นเสมือนจริงแบบอินไลน์เป็นเรื่องที่ไม่สมเหตุสมผลหรือไม่?


172

ฉันได้รับคำถามนี้เมื่อฉันได้รับรหัสตรวจสอบความคิดเห็นว่าฟังก์ชั่นเสมือนไม่จำเป็นต้องอยู่ในบรรทัด

ฉันคิดว่าฟังก์ชั่นเสมือนแบบอินไลน์อาจมีประโยชน์ในสถานการณ์ที่เรียกใช้ฟังก์ชันบนวัตถุโดยตรง แต่ข้อโต้แย้งโต้เถียงกันในใจของฉันก็คือ - ทำไมคนเราถึงต้องการกำหนดเสมือนและใช้วัตถุเพื่อเรียกวิธีการ

เป็นการดีที่สุดที่จะไม่ใช้ฟังก์ชั่นเสมือนแบบอินไลน์เนื่องจากพวกมันแทบไม่เคยขยายเลย

ข้อมูลโค้ดที่ฉันใช้สำหรับการวิเคราะห์:

class Temp
{
public:

    virtual ~Temp()
    {
    }
    virtual void myVirtualFunction() const
    {
        cout<<"Temp::myVirtualFunction"<<endl;
    }

};

class TempDerived : public Temp
{
public:

    void myVirtualFunction() const
    {
        cout<<"TempDerived::myVirtualFunction"<<endl;
    }

};

int main(void) 
{
    TempDerived aDerivedObj;
    //Compiler thinks it's safe to expand the virtual functions
    aDerivedObj.myVirtualFunction();

    //type of object Temp points to is always known;
    //does compiler still expand virtual functions?
    //I doubt compiler would be this much intelligent!
    Temp* pTemp = &aDerivedObj;
    pTemp->myVirtualFunction();

    return 0;
}

1
พิจารณาการคอมไพล์ตัวอย่างด้วยสวิตช์ใดก็ตามที่คุณต้องการเพื่อรับรายชื่อแอสเซมเบลอร์แล้วแสดงผู้ตรวจสอบโค้ดว่าแท้จริงแล้วคอมไพเลอร์สามารถอินไลน์ฟังก์ชั่นเสมือน
โทมัส L Holaday

1
ข้างต้นมักจะไม่ได้รับการ inline เพราะคุณกำลังเรียกฟังก์ชั่นเสมือนจริงในความช่วยเหลือของชั้นฐาน แม้ว่ามันจะขึ้นอยู่กับว่าคอมไพเลอร์นั้นฉลาดแค่ไหน หากสามารถชี้ให้เห็นว่าpTemp->myVirtualFunction()สามารถแก้ไขเป็นการโทรที่ไม่ใช่เสมือนได้อาจมีการโทรในบรรทัดนั้น การอ้างอิงที่อ้างอิงนี้มีการขีดเส้นใต้โดย g ++ 3.4.2: TempDerived & pTemp = aDerivedObj; pTemp.myVirtualFunction();รหัสของคุณไม่ใช่
doc

1
สิ่งหนึ่งที่จริงแล้ว gcc คือการเปรียบเทียบรายการ vtable กับสัญลักษณ์ที่เฉพาะเจาะจงจากนั้นใช้ตัวแปรอินไลน์ในลูปถ้ามันตรงกัน สิ่งนี้มีประโยชน์อย่างยิ่งหากฟังก์ชั่นอินไลน์ว่างเปล่าและสามารถลบลูปได้ในกรณีนี้
Simon Richter

1
@doc Modern compiler พยายามอย่างหนักที่จะหาค่าพอยน์เตอร์ที่เป็นไปได้ในเวลารวบรวม เพียงแค่ใช้ตัวชี้ไม่เพียงพอที่จะป้องกันการอินไลน์ในระดับการปรับให้เหมาะสมที่สำคัญ GCC ยังทำการลดความซับซ้อนที่ศูนย์เพิ่มประสิทธิภาพ!
curiousguy

คำตอบ:


153

ฟังก์ชั่นเสมือนสามารถอินไลน์บางครั้ง ข้อความที่ตัดตอนมาจากC ++ faq ที่ยอดเยี่ยม:

"ครั้งเดียวที่อินไลน์เสมือนการเรียกอินไลน์สามารถทำได้คือเมื่อคอมไพเลอร์รู้" คลาสที่แน่นอน "ของวัตถุซึ่งเป็นเป้าหมายของการเรียกฟังก์ชันเสมือนซึ่งสามารถเกิดขึ้นได้เมื่อคอมไพเลอร์มีวัตถุจริงแทนที่จะเป็นตัวชี้หรือ อ้างอิงไปยังวัตถุเช่นกับวัตถุในพื้นที่วัตถุทั่วโลก / คงที่หรือวัตถุที่มีอยู่ภายในคอมโพสิต "


7
จริง แต่มันก็คุ้มค่าที่จะจำได้ว่าคอมไพเลอร์มีอิสระที่จะเพิกเฉยตัวระบุอินไลน์แม้ว่าการโทรสามารถแก้ไขได้ในเวลารวบรวมและสามารถอินไลน์ได้
sharptooth

6
สถานการณ์อื่นเมื่อฉันคิดว่าการทำอินไลน์สามารถเกิดขึ้นได้คือเมื่อคุณเรียกเมธอดเช่นนี้ -> Temp :: myVirtualFunction () - การเรียกเช่นนี้ข้ามการแก้ปัญหาตารางเสมือนและฟังก์ชั่นควร inline โดยไม่มีปัญหา - ทำไมและถ้าคุณ d ต้องการที่จะทำมันเป็นหัวข้ออื่น :)
RnR

5
@RnR ไม่จำเป็นต้องมี 'this->' เพียงแค่ใช้ชื่อที่ผ่านการรับรองก็เพียงพอแล้ว และพฤติกรรมนี้เกิดขึ้นสำหรับ destructors, constructors และโดยทั่วไปสำหรับผู้ประกอบการที่ได้รับมอบหมาย (ดูคำตอบของฉัน)
ริชาร์ด Corden

2
ชาร์ป - จริง แต่ AFAIK นี่เป็นความจริงของฟังก์ชั่นอินไลน์ทั้งหมดไม่ใช่แค่ฟังก์ชั่นอินไลน์เสมือน
Colen

2
ถือเป็นโมฆะ f (const Base & lhs, const Base & rhs) {} ------ ในการใช้งานฟังก์ชั่นคุณไม่เคยรู้ว่า lhs และ rhs ชี้ไปที่ใดจนกระทั่งถึงรันไทม์
Baiyan Huang

72

เพิ่ม C ++ 11 finalแล้ว สิ่งนี้เปลี่ยนคำตอบที่ยอมรับได้: ไม่จำเป็นต้องทราบคลาสที่แน่นอนของวัตถุอีกต่อไปแล้วก็เพียงพอที่จะทราบว่าวัตถุนั้นมีชนิดคลาสอย่างน้อยซึ่งฟังก์ชันจะประกาศขั้นสุดท้าย:

class A { 
  virtual void foo();
};
class B : public A {
  inline virtual void foo() final { } 
};
class C : public B
{
};

void bar(B const& b) {
  A const& a = b; // Allowed, every B is an A.
  a.foo(); // Call to B::foo() can be inlined, even if b is actually a class C.
}

ไม่สามารถอินไลน์ได้ใน VS 2017
Yola

1
ฉันไม่คิดว่ามันจะทำงานแบบนี้ การเรียกใช้ foo () ผ่านตัวชี้ / การอ้างอิงประเภท A จะไม่สามารถถูกแทรกได้ การโทร b.foo () ควรอนุญาตการอินไลน์ ถ้าคุณไม่แนะนำให้คอมไพเลอร์รู้ว่านี่คือประเภท B เพราะมันรู้บรรทัดก่อนหน้า แต่นั่นไม่ใช่การใช้งานทั่วไป
Jeffrey Faust

ตัวอย่างเช่นเปรียบเทียบโค้ดที่สร้างขึ้นสำหรับแถบและ bas ที่นี่: godbolt.org/g/xy3rNh
Jeffrey Faust

@JeffreyFaust ไม่มีเหตุผลที่ข้อมูลไม่ควรเผยแพร่มี? และiccดูเหมือนว่าจะทำตามลิงค์นั้น
Alexey Romanov

@AlexeyRomanov คอมไพเลอร์มีอิสระในการเพิ่มประสิทธิภาพเกินกว่ามาตรฐานและแน่นอน! สำหรับกรณีง่าย ๆ ดังกล่าวข้างต้นคอมไพเลอร์อาจทราบชนิดและทำการปรับให้เหมาะสมนี้ สิ่งต่าง ๆ นี้ไม่ค่อยเรียบง่ายและมันก็ไม่ใช่เรื่องปกติที่จะสามารถกำหนดชนิดที่แท้จริงของตัวแปร polymorphic ในเวลารวบรวม ฉันคิดว่า OP ใส่ใจกับ 'โดยทั่วไป' ไม่ใช่สำหรับกรณีพิเศษเหล่านี้
Jeffrey Faust

37

มีฟังก์ชั่นเสมือนหนึ่งประเภทที่ยังคงเหมาะสมที่จะให้มีอินไลน์อยู่ พิจารณากรณีต่อไปนี้:

class Base {
public:
  inline virtual ~Base () { }
};

class Derived1 : public Base {
  inline virtual ~Derived1 () { } // Implicitly calls Base::~Base ();
};

class Derived2 : public Derived1 {
  inline virtual ~Derived2 () { } // Implicitly calls Derived1::~Derived1 ();
};

void foo (Base * base) {
  delete base;             // Virtual call
}

การเรียกเพื่อลบ 'ฐาน' จะทำการเรียกเสมือนเพื่อเรียกตัวทำลายคลาสที่ได้รับมาอย่างถูกต้องการโทรนี้จะไม่ถูก inlined อย่างไรก็ตามเนื่องจาก destructor แต่ละตัวเรียกมันว่า parent destructor (ซึ่งในกรณีเหล่านี้ว่างเปล่า) คอมไพเลอร์สามารถอินไลน์การเรียกเหล่านั้นเนื่องจากพวกเขาไม่ได้เรียกฟังก์ชันคลาสพื้นฐานอย่างแท้จริง

มีหลักการเดียวกันสำหรับตัวสร้างคลาสพื้นฐานหรือสำหรับชุดของฟังก์ชันใด ๆ ที่การนำไปปฏิบัติที่ได้รับมานั้นเรียกการใช้งานคลาสพื้นฐาน


23
เราควรตระหนักไว้ว่าการจัดฟันเปล่าไม่ได้หมายความว่าผู้ทำลายจะไม่ทำอะไรเลย Destructors เริ่มต้นทำลายวัตถุสมาชิกทุกคนในคลาสดังนั้นหากคุณมีเวกเตอร์สองสามตัวในคลาสพื้นฐานที่อาจทำงานได้มากในวงเล็บที่ว่างเปล่าเหล่านั้น!
ฟิลิป

14

ฉันเห็นคอมไพเลอร์ที่ไม่ปล่อย v-table ใด ๆ หากไม่มีฟังก์ชั่นที่ไม่ใช่แบบอินไลน์อยู่ (และกำหนดไว้ในไฟล์การนำไปใช้งานหนึ่งไฟล์แทนที่จะเป็นส่วนหัว) พวกเขาจะโยนข้อผิดพลาดที่missing vtable-for-class-Aคล้ายกันหรือคล้ายกันและคุณจะสับสนราวกับว่าฉันเป็น

อันที่จริงมันไม่สอดคล้องกับมาตรฐาน แต่มันเกิดขึ้นดังนั้นให้พิจารณาอย่างน้อยหนึ่งฟังก์ชั่นเสมือนจริงไม่ได้อยู่ในส่วนหัว gccฉันรู้ว่ามันเกิดขึ้นกับบางรุ่น

ตามที่มีคนกล่าวถึงฟังก์ชั่นอินไลน์เสมือนอาจเป็นประโยชน์ในบางครั้งแต่แน่นอนว่าส่วนใหญ่คุณจะใช้มันเมื่อคุณไม่รู้จักชนิดไดนามิกของวัตถุเพราะนั่นคือเหตุผลทั้งหมดvirtualในตอนแรก

คอมไพเลอร์ inlineแต่ไม่สามารถสมบูรณ์ไม่สนใจ มันมีความหมายอื่น ๆ นอกเหนือจากการเร่งการเรียกใช้ฟังก์ชัน อินไลน์โดยปริยายสำหรับคำจำกัดความในชั้นเรียนเป็นกลไกที่ช่วยให้คุณสามารถใส่ความหมายลงในส่วนหัว: เฉพาะinlineฟังก์ชั่นสามารถกำหนดหลายครั้งตลอดโปรแกรมทั้งหมดโดยไม่ละเมิดกฎใด ๆ ในท้ายที่สุดมันจะทำงานตามที่คุณกำหนดไว้เพียงครั้งเดียวในโปรแกรมทั้งหมดแม้ว่าคุณจะรวมส่วนหัวหลาย ๆ ครั้งในไฟล์ต่าง ๆ ที่เชื่อมโยงเข้าด้วยกัน


11

ที่จริงแล้วฟังก์ชั่นเสมือนจริงสามารถถูกแทรกได้ตราบใดที่มันถูกเชื่อมโยงกันแบบคงที่: สมมติว่าเรามีคลาสนามธรรมที่Base มีฟังก์ชั่นเสมือนFและคลาสที่ได้รับDerived1และDerived2:

class Base {
  virtual void F() = 0;
};

class Derived1 : public Base {
  virtual void F();
};

class Derived2 : public Base {
  virtual void F();
};

การโทรแบบ hypotetical b->F();(ด้วยbชนิดBase*) นั้นชัดเจนว่าเป็นเสมือน แต่คุณ (หรือคอมไพเลอร์ ... ) สามารถเขียนใหม่ได้เช่นนั้น (สมมติว่าtypeofเป็นtypeidฟังก์ชั่นเหมือนที่คืนค่าที่สามารถใช้ในswitch)

switch (typeof(b)) {
  case Derived1: b->Derived1::F(); break; // static, inlineable call
  case Derived2: b->Derived2::F(); break; // static, inlineable call
  case Base:     assert(!"pure virtual function call!");
  default:       b->F(); break; // virtual call (dyn-loaded code)
}

ในขณะที่เรายังต้องการ RTTI สำหรับการtypeofโทรนั้นสามารถถูก inline อย่างมีประสิทธิภาพโดยทั่วไปฝัง vtable ภายในกระแสการเรียนการสอนและเชี่ยวชาญการโทรสำหรับคลาสที่เกี่ยวข้องทั้งหมด สิ่งนี้สามารถสรุปได้โดยผู้เชี่ยวชาญเพียงไม่กี่คลาส (พูดเพียงDerived1):

switch (typeof(b)) {
  case Derived1: b->Derived1::F(); break; // hot path
  default:       b->F(); break; // default virtual call, cold path
}

พวกเขามีคอมไพเลอร์ที่ทำสิ่งนี้หรือไม่? หรือนี่เป็นการเก็งกำไร ขออภัยถ้าฉันสงสัยมากเกินไป แต่เสียงของคุณในคำอธิบายข้างต้นดูเหมือนว่า - "พวกเขาสามารถทำได้โดยสิ้นเชิง!" ซึ่งแตกต่างจาก "ผู้รวบรวมบางคนทำสิ่งนี้"
Alex

ใช่ Graal ทำอินไลน์แบบ polymorphic (เช่นสำหรับ LLVM bitcode ผ่าน Sulong)
CAFxX

4

การทำเครื่องหมายวิธีเสมือนแบบอินไลน์ช่วยในการเพิ่มประสิทธิภาพฟังก์ชั่นเสมือนจริงในสองกรณีต่อไปนี้:


3

อินไลน์ไม่ได้ทำอะไรเลย - เป็นคำใบ้ คอมไพเลอร์อาจเพิกเฉยหรืออาจอินไลน์เหตุการณ์การโทรโดยไม่มีอินไลน์หากเห็นการปรับใช้และชอบแนวคิดนี้ หากความคมชัดของรหัสอยู่ที่เสาเข็มอินไลน์ควรจะถูกลบออก


2
สำหรับคอมไพเลอร์ที่ทำงานบน TUs เดียวเท่านั้นพวกมันสามารถทำหน้าที่อินไลน์โดยนัยที่มีคำจำกัดความ ฟังก์ชั่นสามารถกำหนดได้ใน TU หลาย ๆ อันเท่านั้นหากคุณทำให้เป็นแบบอินไลน์ 'อินไลน์' เป็นมากกว่าคำใบ้และสามารถปรับปรุงประสิทธิภาพได้อย่างน่าทึ่งสำหรับการสร้าง g ++ / makefile
Richard Corden

3

ฟังก์ชั่นเสมือนที่ประกาศแล้วจะถูก inlined เมื่อเรียกผ่านวัตถุและละเว้นเมื่อเรียกผ่านตัวชี้หรือการอ้างอิง


1

ด้วยคอมไพเลอร์สมัยใหม่มันจะไม่ทำอันตรายใด ๆ คอมโบของคอมไพเลอร์ / ลิงเกอร์อาจสร้าง vtables หลายอัน แต่ฉันไม่เชื่อว่ามันจะเป็นปัญหาอีกต่อไป


1

คอมไพเลอร์สามารถอินไลน์ฟังก์ชั่นเฉพาะเมื่อการโทรสามารถแก้ไขได้อย่างชัดเจนในเวลารวบรวม

ฟังก์ชันเสมือนอย่างไรก็ตามได้รับการแก้ไขที่รันไทม์ดังนั้นคอมไพเลอร์จึงไม่สามารถอินไลน์การโทรได้เนื่องจากชนิดคอมไพล์ชนิดไดนามิก (ดังนั้นจึงไม่สามารถกำหนดฟังก์ชั่นการใช้งานได้)


1
เมื่อคุณเรียกใช้เมธอดคลาสพื้นฐานจากคลาสเดียวกันหรือคลาสที่ได้รับการโทรนั้นจะไม่คลุมเครือและไม่ใช่แบบเสมือน
ชาร์ปคม

1
@sharptooth: แต่มันจะเป็นวิธีการอินไลน์ที่ไม่ใช่เสมือน คอมไพเลอร์สามารถใช้ฟังก์ชั่นอินไลน์ที่คุณไม่ได้ขอให้มันและมันอาจจะรู้ดีกว่าว่าจะอินไลน์หรือไม่ ให้มันตัดสินใจ
David Rodríguez - dribeas

1
@dribeas: ใช่นั่นคือสิ่งที่ฉันกำลังพูดถึง ฉันคัดค้านคำแถลงว่า finctions เสมือนได้รับการแก้ไขที่รันไทม์ - นี่เป็นความจริงเฉพาะเมื่อมีการโทรเสร็จจริงไม่ใช่สำหรับคลาสที่แน่นอน
sharptooth

ฉันเชื่อว่าเป็นเรื่องไร้สาระ ฟังก์ชั่นใด ๆ สามารถถูกแทรกได้เสมอไม่ว่ามันจะใหญ่แค่ไหนหรือว่ามันเสมือนจริงหรือไม่ก็ตาม มันขึ้นอยู่กับวิธีการเขียนคอมไพเลอร์ หากคุณไม่เห็นด้วยฉันคาดหวังว่าคอมไพเลอร์ของคุณจะไม่สามารถสร้างโค้ดที่ไม่มีอินไลน์ได้ นั่นคือ: คอมไพเลอร์สามารถรวมรหัสที่เวลาทดสอบรันไทม์สำหรับเงื่อนไขที่ไม่สามารถแก้ไขได้ในเวลาคอมไพล์ มันก็เหมือนกับคอมไพเลอร์สมัยใหม่ที่สามารถแก้ไขค่าคงที่ / ลดการแสดงออก nummeric ในเวลารวบรวม หากฟังก์ชั่น / วิธีการไม่ได้ inline ก็ไม่ได้หมายความว่ามันไม่สามารถ inline

1

ในกรณีที่การเรียกใช้ฟังก์ชั่นนั้นไม่คลุมเครือและเป็นฟังก์ชั่นที่เหมาะสมสำหรับการทำอินไลน์คอมไพเลอร์นั้นฉลาดพอที่จะอินไลน์โค้ดได้

เวลาที่เหลือ "inline virtual" นั้นเป็นเรื่องไร้สาระและแน่นอนว่าผู้รวบรวมบางรายจะไม่รวบรวมรหัสนั้น


g ++ รุ่นใดที่ไม่รวมอินไลน์เสมือน
โทมัส L Holaday

ฮึ่ม 4.1.1 ฉันมีตอนนี้ดูเหมือนจะมีความสุข ฉันแรกพบปัญหากับ codebase นี้โดยใช้ 4.0.x เดาว่าข้อมูลของฉันล้าสมัยแก้ไขแล้ว
moonshadow

0

มันสมเหตุสมผลที่จะทำให้ฟังก์ชั่นเสมือนจริงและจากนั้นเรียกพวกเขาบนวัตถุมากกว่าการอ้างอิงหรือพอยน์เตอร์ Scott Meyer แนะนำในหนังสือ "Effective c ++" เพื่อไม่ให้นิยามฟังก์ชันที่ไม่ใช่เสมือนที่สืบทอดมา นั่นทำให้รู้สึกเพราะเมื่อคุณสร้างคลาสที่มีฟังก์ชั่นที่ไม่ใช่เสมือนและกำหนดฟังก์ชั่นใหม่ในคลาสที่ได้รับคุณอาจต้องใช้อย่างถูกต้องด้วยตัวคุณเอง แต่คุณไม่แน่ใจว่าคนอื่นจะใช้อย่างถูกต้อง นอกจากนี้คุณอาจใช้มันในภายหลังได้อย่างไม่ถูกต้อง ดังนั้นถ้าคุณสร้างฟังก์ชั่นในคลาสพื้นฐานและคุณต้องการให้มันสามารถ Redifinable คุณควรทำให้มันเป็นเสมือน ถ้ามันเหมาะสมที่จะสร้างฟังก์ชั่นเสมือนจริงและเรียกพวกมันบนวัตถุมันก็สมเหตุสมผลที่จะอินไลน์พวกมัน


0

ที่จริงแล้วในบางกรณีการเพิ่ม "อินไลน์" ในการแทนที่สุดท้ายเสมือนสามารถทำให้โค้ดของคุณไม่ได้รับการคอมไพล์ได้ดังนั้นบางครั้งก็มีความแตกต่าง (อย่างน้อยใน VS2017s คอมไพเลอร์)!

จริงๆแล้วฉันกำลังทำฟังก์ชั่นการแทนที่สุดท้ายแบบอินไลน์เสมือนใน VS2017 เพิ่มมาตรฐาน c ++ 17 เพื่อรวบรวมและเชื่อมโยงและด้วยเหตุผลบางอย่างมันล้มเหลวเมื่อฉันใช้สองโครงการ

ฉันมีโครงการทดสอบและการติดตั้ง DLL ที่ฉันกำลังทำการทดสอบหน่วย ในโครงการทดสอบฉันมีไฟล์ "linker_includes.cpp" ที่ #include ไฟล์ * .cpp จากโครงการอื่นที่จำเป็น ฉันรู้ ... ฉันรู้ว่าฉันสามารถตั้งค่า msbuild ให้ใช้ไฟล์วัตถุจาก DLL ได้ แต่โปรดจำไว้ว่ามันเป็นโซลูชันเฉพาะของไมโครซอฟท์ในขณะที่การรวมไฟล์ cpp นั้นไม่เกี่ยวข้องกับการสร้างระบบและรุ่นอื่น ๆ อีกมากมาย ไฟล์ cpp กว่าไฟล์ xml และการตั้งค่าโครงการและ ...

สิ่งที่น่าสนใจคือฉันได้รับข้อผิดพลาด linker จากโครงการทดสอบอย่างต่อเนื่อง แม้ว่าฉันจะเพิ่มคำจำกัดความของฟังก์ชั่นที่ขาดหายไปโดยการคัดลอกวางและไม่รวมถึง! แปลกมาก โครงการอื่นได้สร้างขึ้นและไม่มีการเชื่อมต่อระหว่างทั้งสองนอกเหนือจากการทำเครื่องหมายการอ้างอิงโครงการดังนั้นจึงมีคำสั่งสร้างเพื่อให้แน่ใจว่าทั้งสองถูกสร้างขึ้น ...

ฉันคิดว่ามันเป็นบั๊กในคอมไพเลอร์ ฉันไม่รู้ว่ามีอยู่ในคอมไพเลอร์ที่จัดส่งมาพร้อมกับ VS2020 หรือไม่เพราะฉันใช้เวอร์ชั่นที่เก่ากว่าเพราะ SDK บางตัวนั้นใช้ได้กับ :-(

ฉันแค่อยากจะเพิ่มที่ไม่เพียง แต่ทำเครื่องหมายพวกเขาเป็นแบบอินไลน์อาจหมายถึงบางสิ่ง แต่อาจทำให้โค้ดของคุณไม่ได้สร้างในบางสถานการณ์ที่หายาก! นี่เป็นเรื่องแปลก แต่ก็รู้ดี

ป.ล. : รหัสที่ฉันกำลังทำอยู่คือคอมพิวเตอร์กราฟิกที่เกี่ยวข้องดังนั้นฉันจึงชอบอินไลน์และนั่นคือสาเหตุที่ฉันใช้ทั้งขั้นตอนสุดท้ายและแบบอินไลน์ ฉันเก็บ specifier สุดท้ายเพื่อหวังว่า build build จะฉลาดพอที่จะสร้าง DLL ได้โดยการฝังไว้แม้จะไม่มีฉันก็บอกใบ้โดยตรง ...

PS (Linux): ฉันคาดหวังว่าสิ่งเดียวกันจะไม่เกิดขึ้นใน gcc หรือเสียงดังกราวด์เพราะฉันเคยทำสิ่งเหล่านี้เป็นประจำ ฉันไม่แน่ใจว่าปัญหานี้มาจากที่ใด ... ฉันชอบทำ c ++ บน Linux หรืออย่างน้อยก็มี gcc บ้าง แต่บางครั้งโครงการก็แตกต่างกันตามความต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.