Bagaimana cara memeriksa dengan benar apakah std :: function kosong di C ++ 11?

99

Saya bertanya-tanya bagaimana cara memeriksa dengan benar apakah std::functionkosong. Pertimbangkan contoh ini:

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

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

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

Kode ini dikompilasi dengan baik di MSVC tetapi jika saya memanggil doSomething()tanpa menginisialisasi eventFunckode tersebut jelas macet. Itu diharapkan tapi saya bertanya-tanya apa nilai dari itu eventFunc? Kata debugger 'empty'. Jadi saya memperbaikinya menggunakan pernyataan if sederhana:

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

Ini berfungsi tetapi saya masih bertanya-tanya apa nilai non-inisialisasi std::function? Saya ingin menulis if (eventFunc != nullptr)tetapi std::function(jelas) bukan penunjuk.

Mengapa murni jika berhasil? Apa keajaiban di baliknya? Dan, apakah ini cara yang benar untuk memeriksanya?

NightElfik
sumber
8
Perhatikan bahwa eventFuncitu bukanlah lambda; itu a std::function. Anda dapat menyimpan lambda dalam std::functions, tetapi keduanya tidak sama.
templatetypedef
3
Anda benar, saya mengubah judul untuk menghindari kebingungan. Terima kasih.
NightElfik

Jawaban:

107

Anda tidak memeriksa lambda kosong, tetapi apakah std::functionmemiliki target yang dapat dipanggil yang disimpan di dalamnya. Pemeriksaan ini terdefinisi dengan baik dan berfungsi karena std::function::operator boolmemungkinkan konversi implisit ke booldalam konteks di mana nilai boolean diperlukan (seperti ekspresi bersyarat dalam ifpernyataan).

Selain itu, gagasan tentang lambda kosong tidak masuk akal. Di balik layar, kompilator mengubah ekspresi lambda menjadi definisi struct(atau class), dengan variabel yang Anda tangkap disimpan sebagai anggota data ini struct. Operator panggilan fungsi publik juga ditentukan, yang memungkinkan Anda memanggil lambda. Jadi, apa lambda kosong itu?


Anda juga dapat menulis if(eventFunc != nullptr)jika Anda mau, ini setara dengan kode yang Anda miliki dalam pertanyaan. std::function mendefinisikan operator== dan operator!=kelebihan untuk membandingkan dengan a nullptr_t.

Praetorian
sumber
1
Tapi tidakkah == nullptrmelakukan hal yang sama? Sepertinya ada seharusnya menjadi kelebihan bagi ==operator yang menyebabkan "kosong" std::functionuntuk membandingkan trueterhadap nullptr: cplusplus.com/reference/functional/function/operators
Kyle Strand
3
@KStrand Ya, membandingkan dengan nullptrakan bekerja juga, if(eventFunc != nullptr)sama dengan if(eventFunc)pertanyaan di atas.
Praetorian
3
Secara teknis, std::function::operator booltidak mengizinkan konversi implisit ke bool. Ini ditandai explicit, tetapi standar membuat pengecualian untuk konstruksi bahasa tertentu yang mengharapkan ekspresi boolean, menyebutnya "secara kontekstual dikonversi ke bool." Anda dapat menemukan potongan yang relevan dari bahasa standar dan penjelasannya di sini: chris-sharpe.blogspot.com/2013/07/…
bcrist
@bcrist Ya, saya sadar bahwa operator konversi boolean adalah explicit, itulah mengapa saya berhati-hati untuk menyatakan mengizinkan konversi implisit ke booldalam konteks di mana nilai boolean diperlukan . Persis seperti inilah yang terjadi pada kode yang dipermasalahkan.
Praetorian
5
@Praetorian Hal yang ingin saya sampaikan adalah bahwa standar memberikan arti yang sangat spesifik pada frase "konversi implisit", dan ini sangat berbeda dari "konversi kontekstual ke bool," yang juga memiliki arti yang sangat spesifik. Tidak ada hubungan "Is-a" di sini. Saya mengerti bahwa pemula mungkin tidak perlu langsung mengetahui perbedaan antara konversi implisit / eksplisit / kontekstual, tetapi lebih baik mempelajari kata-kata yang tepat secara tidak sadar, daripada harus menghentikan kebiasaan lama nanti.
bcrist
22

Periksa di sini http://www.cplusplus.com/reference/functional/function/operator_bool/

Contoh

// 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;
}

Keluaran

foo tidak bisa dipanggil.

bar bisa dipanggil.

Dawid Drozd
sumber
31
Saya pikir jawaban ini akan lebih jelas tanpa swap(). Saya berpikir hasilnya mundur sampai saya menyadarinya.
cp.engr
0

(Izinkan saya memberikan jawaban yang jelas.)

Anda dapat memeriksa apakah a std::functionkosong dengan std::function::operator bool.

true: jika objek dapat dipanggil.
false: jika tidak (objek adalah fungsi kosong)

Contoh

#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;
}

Keluaran

foo tidak kosong.
bar kosong.

zwcloud
sumber
2
String hasil Anda ditukar.
Sophit
@Sophit Apakah Anda yakin? ;)
zwcloud
1
Komentar Anda mengatakan foo tidak kosong dan hasilnya tidak sesuai. Saya setuju dengan komentar anda
Sophit