จะตรวจสอบได้อย่างไรว่า std :: function ว่างใน C ++ 11 หรือไม่?


99

ฉันสงสัยว่าจะตรวจสอบอย่างไรว่าstd::functionว่างเปล่า ลองพิจารณาตัวอย่างนี้:

class Test {
    std::function<void(int a)> eventFunc;

    void registerEvent(std::function<void(int a)> e) {
        eventFunc = e;
    }

    void doSomething() {
        ...
        eventFunc(42);
    }
};

รหัสนี้รวบรวมได้ดีใน MSVC แต่ถ้าฉันโทรdoSomething()โดยไม่เริ่มต้นeventFuncรหัสจะขัดข้องอย่างเห็นได้ชัด เป็นที่คาดหวัง แต่ฉันสงสัยว่าค่าของeventFunc? 'empty'ดีบักเกอร์กล่าวว่า ดังนั้นฉันจึงแก้ไขโดยใช้คำสั่ง if ง่ายๆ:

   void doSomething() {
        ...
        if (eventFunc) {
            eventFunc(42);
        }
   }

ใช้งานได้ แต่ฉันยังสงสัยว่าค่าของการไม่เริ่มต้นstd::functionคืออะไร? ฉันอยากจะเขียนif (eventFunc != nullptr)แต่std::function(ชัด ๆ ) ไม่ใช่ตัวชี้

ทำไม Pure if ทำงาน? ความมหัศจรรย์ที่อยู่เบื้องหลังมันคืออะไร? และเป็นวิธีตรวจสอบที่ถูกต้องหรือไม่?


8
สังเกตว่าeventFuncไม่ใช่แลมด้า มันคือstd::function. คุณสามารถจัดเก็บ lambdas ในstd::functions ได้ แต่ไม่ใช่สิ่งเดียวกัน
templatetypedef

3
คุณพูดถูกฉันเปลี่ยนชื่อเรื่องเพื่อไม่ให้สับสน ขอบคุณ.
NightElfik

คำตอบ:


107

คุณไม่ได้ตรวจหาแลมด้าเปล่า แต่std::functionมีเป้าหมายที่เรียกได้เก็บไว้หรือไม่ การตรวจสอบมีการกำหนดไว้อย่างชัดเจนและใช้งานได้เนื่องจากstd::function::operator boolอนุญาตให้มีการแปลงโดยนัยเป็นboolในบริบทที่ต้องใช้ค่าบูลีน (เช่นนิพจน์เงื่อนไขในifคำสั่ง)

นอกจากนี้ความคิดของแลมด้าที่ว่างเปล่าก็ไม่สมเหตุสมผล เบื้องหลังคอมไพเลอร์จะแปลงการแสดงออกแลมบ์ดาเป็นstruct(หรือclass) structความหมายกับตัวแปรคุณสามารถจับภาพเก็บไว้เป็นข้อมูลสมาชิกนี้ นอกจากนี้ยังมีการกำหนดตัวดำเนินการเรียกใช้ฟังก์ชันสาธารณะซึ่งเป็นสิ่งที่อนุญาตให้คุณเรียกใช้แลมด้า แลมด้าที่ว่างเปล่าจะเป็นอย่างไร?


คุณยังสามารถเขียนได้if(eventFunc != nullptr)หากต้องการซึ่งเทียบเท่ากับรหัสที่คุณมีในคำถาม std::function กำหนด operator==และoperator!=เกินสำหรับการเปรียบเทียบกับnullptr_t.


1
ไม่ได้== nullptrทำสิ่งเดียวกัน แต่? ดูเหมือนว่าจะมีการโอเวอร์โหลดสำหรับตัว==ดำเนินการที่ทำให้เกิด "ว่าง" std::functionเพื่อเปรียบเทียบtrueกับnullptr: cplusplus.com/reference/functional/function/operators
Kyle Strand

3
@KyleStrand ใช่การเปรียบเทียบกับnullptrจะใช้ได้ผลเหมือนif(eventFunc != nullptr)กันกับif(eventFunc)คำถามข้างต้น
Praetorian

3
เทคนิคไม่อนุญาตให้มีการแปลงนัยไปstd::function::operator bool boolมันถูกทำเครื่องหมายไว้explicitทั้งหมด แต่มาตรฐานทำให้เกิดข้อยกเว้นสำหรับโครงสร้างภาษาบางอย่างที่คาดหวังนิพจน์บูลีนเรียกมันว่า "บริบทที่แปลงเป็นบูล" คุณสามารถค้นหาตัวอย่างมาตรฐานที่เกี่ยวข้องและคำอธิบายได้ที่นี่: chris-sharpe.blogspot.com/2013/07/…
bcrist

@bcrist ครับผมทราบว่าผู้ประกอบการแปลงบูลเป็นexplicitที่ว่าทำไมผมระมัดระวังในการรัฐช่วยให้การแปลงส่อไปboolในบริบทที่จะต้องค่าบูลีน นี่คือสิ่งที่เกิดขึ้นในโค้ดที่เป็นปัญหา
Praetorian

5
@Praetorian ประเด็นที่ฉันพยายามทำคือมาตรฐานกำหนดความหมายที่เฉพาะเจาะจงมากให้กับวลี "การแปลงโดยนัย" และแตกต่างอย่างชัดเจนจาก "การแปลงบริบทเป็นบูล" ซึ่งมีความหมายที่เฉพาะเจาะจงมากเช่นกัน ที่นี่ไม่มีความสัมพันธ์ "Is-a" ฉันเข้าใจว่าผู้เริ่มต้นอาจไม่จำเป็นต้องรู้ความแตกต่างระหว่างการแปลงโดยนัย / ชัดเจน / บริบททันที แต่จะดีกว่าถ้าเรียนรู้คำศัพท์ที่ถูกต้องโดยไม่รู้ตัวแทนที่จะต้องเลิกนิสัยเก่า ๆ ในภายหลัง
bcrist

22

ตรวจสอบที่นี่http://www.cplusplus.com/reference/functional/function/operator_bool/

ตัวอย่าง

// function::operator bool example
#include <iostream>     // std::cout
#include <functional>   // std::function, std::plus

int main () {
  std::function<int(int,int)> foo,bar;
  foo = std::plus<int>();

  foo.swap(bar);

  std::cout << "foo is " << (foo ? "callable" : "not callable") << ".\n";
  std::cout << "bar is " << (bar ? "callable" : "not callable") << ".\n";

  return 0;
}

เอาต์พุต

foo ไม่สามารถเรียกได้

บาร์สามารถโทรได้


31
ฉันคิดว่าคำตอบนี้จะชัดเจนยิ่งขึ้นหากไม่มีswap(). ฉันคิดว่าผลลัพธ์จะถอยหลังจนกว่าฉันจะรู้ตัว
cp.engr

0

(ให้ฉันตอบที่ชัดเจน)

คุณสามารถตรวจสอบว่า a std::functionว่างเปล่าด้วยstd::function::operator bool.

จริง: ถ้าวัตถุนั้นสามารถเรียกใช้ได้
เท็จ: มิฉะนั้น (วัตถุเป็นฟังก์ชันว่าง)

ตัวอย่าง

#include <iostream>
#include <functional>

int main ()
{
    std::function<int(int,int)> foo = std::plus<int>();//assigned: not empty
    std::function<int(int,int)> bar;//not assigned: empty

    std::cout << "foo is " << (foo ? "not empty" : "empty") << ".\n";
    std::cout << "bar is " << (bar ? "not empty" : "empty") << ".\n";

    return 0;
}

เอาต์พุต

foo ไม่ว่างเปล่า
แถบว่างเปล่า


2
สตริงผลลัพธ์ของคุณถูกสลับ
โสภิต

@ โสภิตแน่ใจหรือ ;)
zwcloud

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