Cara menghindari konversi implisit dari int (0) ke penunjuk dalam vektor

9

Ada situasi di mana saya ingin mengumpulkan semua nama node jalur ke kunci di JSON. Pertimbangkan kondisi indeks array "0", "1" juga diperbolehkan, tetapi mudah untuk melupakan tanda kutip, yang akan menyebabkan crash ketika melakukan dereference. Jadi saya ingin menolak ini. Contoh:

#include <vector>
#include <iostream>

int func(const std::vector<const char*>& pin) {
    return pin.size();
}

int main() {
    // {"aname", "3", "path", "0"} wanted but this still compile
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}

Saya menemukan dan mencoba ini. Bagaimana cara menghindari konversi tersirat pada fungsi yang tidak membangun? sebagai berikut:

#include <vector>
#include <iostream>

int func(const std::vector<const char*>& pin) {
    return pin.size();
}

template<typename T>
int func(T pin) = delete;

int main() {
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}

Tetapi kompiler masih tidak mengerti saya.

Ada saran?
Tolong tunjukkan penyalahgunaan terminologi dan asumsi, terima kasih!

rustyhu
sumber
apakah ada alasan mengapa Anda menggunakan std::vector<const char*>bukan std::vector<std::string>>?
bolov
Apakah Anda ingin melarang nullptrjuga?
Jarod42
@bolov Pada awalnya saya mempertimbangkan untuk meneruskan nama-nama simpul ini ke antarmuka analisis JSON, yang menggunakan karakter C-style * sebagai input, tetapi ini tidak terbatas di sini. Saya telah menguji, menggunakan std :: vector <std :: string >> masih menerima 0 ketika mengkompilasi, tetapi crash ketika dijalankan, pada mesin saya GCC melaporkan "basic_string :: _ M_construct null not valid".
rustyhu
@ Jarod42 Ya, yang diinginkan adalah string C-style literal.
rustyhu

Jawaban:

9

Sesuatu seperti ini? Ini sangat mirip dengan solusi kelebihan yang Anda sarankan, tetapi membutuhkan pembungkus jenis vektor. Gagal membangun jika Anda memberikan literal0 karena kelebihan konstruktor yang dihapus dipilih.

#include <memory>
#include <new>
#include <vector>
#include <iostream>
using std::vector;

template<typename T>
struct no_zero {
        no_zero(T val) : val(val) {}
        no_zero(int val) = delete;
        operator T() { return val; }
        T val;
};

int func(const vector<no_zero<const char*> >& pin) {
    return pin.size();
}

int main() {
    // {"aname", "3", "path", "0"} wanted but this still compile
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}
Mikel Rychliski
sumber
4

Di belakang, banyak konversi implisit dalam C ++ sangat disayangkan, ini menjadi salah satunya.

Satu opsi untuk dipertimbangkan adalah -Wzero-as-null-pointer-constant pada gcc dan dentang. Hati-hati karena ini mengubah perilaku program standar dan jika diaktifkan secara global dapat memiliki beberapa efek yang tidak diinginkan.

g ++ - bagaimana cara menonaktifkan konversi implisit dari 0 ke tipe pointer?

Peringatan Dentang manakah yang setara dengan Wzero-as-null-pointer-constant dari GCC?

bolov
sumber