Pertanyaan Mengapa lambdas generatif diperbolehkan sementara struct bersarang dengan metode templated tidak?


Sejauh yang saya pahami - lambdas generik diubah menjadi objek dari struct lingkup lokal dengan templated operator(). Hal ini membuat lambda generik sangat kuat dan mudah digunakan. Di sisi lain satu dapat membuat struct bersarang ke fungsi, namun bagaimanapun struct memiliki anggota templated misalnya:

#include <iostream>

int main() {
    struct inner {
    template <class T>
       void operator()(T &&i) { }
    };
    return 0;
}

atau templated dengan sendirinya:

int main() {
    template <class T>
    struct inner {
       void operator()(T &&i) { }
    };
    return 0;
}

kompiler tampaknya memiliki masalah dengan kompilasi:

error: invalid declaration of member template in local class

dan

error: a template declaration cannot appear at block scope

Saya menganggap masalah meletakkan lebih dalam c + + standar daripada di bug kompiler. Apa alasan lambdas diizinkan untuk memiliki anggota templated dan bukan struktur lokal?

saya menemukan qustion ini, tapi saya pikir jawabannya agak ketinggalan jaman (saya tidak berpikir itu benar bahkan untuk c ++ 11).


32
2017-10-25 14:19


asal


Jawaban:


Ini adalah masalah inti 728, yang diajukan sebelum lambdas generik adalah suatu hal.

Anda menyebutkan lambdas generik dan bahwa mereka identik dengan kelas lokal dengan anggota yang terkait template operator(). Namun, sebenarnya tidak, dan perbedaannya terkait dengan karakteristik implementasi. Mempertimbangkan

template <typename T>
class X {
    template <typename>
    void foo() {
        T t;
    }
};

Dan

template <typename T>
auto bar() {
    return [] (auto) {T t;};
};

Instansiasi template ini dengan <void> akan baik-baik saja dalam kasus pertama, tetapi tidak terbentuk di yang kedua. Mengapa baik dalam kasus pertama? foo tidak perlu instantiable untuk masing-masing T, tetapi hanya salah satu dari mereka (ini akan menjadi [temp.res] / (8.1)).

Mengapa tidak terbentuk dalam kasus kedua? Tubuh lambda generik adalah instantiated - sebagian - menggunakan argumen template yang disediakan. Dan alasan untuk instantiasi parsial ini adalah kenyataan bahwa ...

... lingkup leksikal yang digunakan saat memproses definisi fungsi pada dasarnya bersifat sementara, yang berarti penundaan instantiasi beberapa bagian dari definisi template fungsi sulit untuk didukung.

(Richard Smith) Kita harus memberi contoh yang cukup dari "templat" lokal untuk membuatnya independen dari konteks lokal (yang mencakup parameter templat dari templat fungsi yang dilampirkan).

Ini juga terkait dengan alasan untuk [expr.prim.lambda] / 13, yang mengamanatkan bahwa entitas secara implisit ditangkap oleh lambda jika ...

nama entitas dalam ekspresi yang berpotensi dievaluasi ([basic.def.odr]) di mana melampirkan ekspresi penuh tergantung pada parameter lambda generik yang dinyatakan dalam jangkauan jangkauan ekspresi lambda.

Artinya, jika saya memiliki lambda suka [=] (auto x) {return (typename decltype(x)::type)a;}, dimana a adalah beberapa variabel blok-ruang lingkup dari fungsi melampirkan, terlepas dari apakah xadalah typedef anggota untuk void atau tidak, para pemain akan menyebabkan penangkapan a, karena kita harus memutuskan ini tanpa menunggu doa dari lambda. Untuk diskusi tentang masalah ini, lihat proposal asli tentang lambdas generik.

Intinya adalah bahwa penundaan sepenuhnya instantiasi template anggota tidak kompatibel dengan model yang digunakan oleh (setidaknya satu) implementasi utama, dan karena semantik yang diharapkan, fitur itu tidak diperkenalkan.


Apakah itu motivasi asli untuk kendala ini? Itu diperkenalkan antara Januari dan Mei 1994, tanpa kertas yang menutupinya, jadi kita hanya bisa mendapatkan gambaran kasar dari pengertian yang berlaku dari kertas inipembenaran mengapa kelas lokal tidak akan menjadi argumen template:

Template kelas dan kelas yang dihasilkan dari template adalah cakupan global   entitas dan tidak dapat merujuk ke entitas lingkup lokal.

Mungkin saat itu, seseorang ingin KISS.


27
2017-10-25 15:28



Saya menganggap masalah meletakkan lebih dalam c ++ standar

Benar. Ini ditetapkan dalam [temp] untuk kelas template:

SEBUAH deklarasi template hanya dapat muncul sebagai ruang lingkup namespace atau deklarasi lingkup kelas.

dan [temp.mem] untuk templat anggota:

Kelas lokal tipe non-penutupan tidak boleh memiliki templat anggota.


Apa alasan lambdas diizinkan untuk memiliki anggota templated dan bukan struktur lokal?

Karena begitu kita memiliki lambdas di C ++ 11, maka akan sangat berguna untuk memperluas konsep itu agar memiliki lambdas generik. Ada a usul untuk ekstensi bahasa seperti itu, yang mana direvisi  dan direvisi dan diadopsi.

Di sisi lain, belum ada proposal yang disajikan (sejauh yang saya ketahui dari pencarian singkat) yang menjabarkan motivasi untuk kebutuhan templat anggota di kelas lokal yang tidak cukup dipecahkan oleh lambda generik. .

Jika Anda merasa bahwa ini adalah masalah penting yang perlu dipecahkan, jangan ragu untuk melakukannya kirimkan proposal setelah meletakkan motivasi yang bijaksana untuk mengapa templat anggota lokal penting.


3
2017-10-25 15:23