Jak uniknąć niejawnej konwersji z liczby całkowitej 0 na wskaźnik, jako elementu wektora

11

Jest sytuacja, w której chcę zebrać wszystkie nazwy węzłów ścieżki do klucza w JSON. Zastanów się nad warunkiem, że indeks tablicy „0”, „1” są również dozwolone, ale łatwo jest zapomnieć o cudzysłowach, co doprowadziłoby do awarii, gdy dereferencja. Więc chcę to odrzucić. Przykład:

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

Znalazłem i wypróbowałem to Jak uniknąć niejawnej konwersji na funkcje niebędące konstruktorami? jak następuje:

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

Ale kompilator wciąż mnie nie rozumiał.

Jakieś sugestie?
Proszę wskazać wszelkie niewłaściwe użycie terminologii i założeń, dziękuję!

rustyhu
źródło
czy istnieje powód, dla którego używasz std::vector<const char*>zamiast std::vector<std::string>>?
bolov
Czy też chcesz zabronić nullptr?
Jarod42
@bolov Na początku rozważam przekazanie nazw tych węzłów do interfejsu analizy JSON, który wykorzystuje dane wejściowe char * w stylu C, ale nie jest to tutaj ograniczone. Przetestowałem, używając std :: vector <std :: string >> nadal akceptuje 0 podczas kompilacji, ale zawiesza się po uruchomieniu, na moim komputerze GCC zgłasza „basic_string :: _ M_construct null niepoprawny”.
rustyhu
@ Jarod42 Tak, czego chcę literał ciąg znaków w stylu C.
rustyhu

Odpowiedzi:

10

Coś takiego? Jest bardzo podobny do proponowanego rozwiązania przeciążeniowego, ale wymaga zawinięcia typu wektora. Nie można zbudować, jeśli podasz literał, 0ponieważ wybrano przeciążenie usuniętego konstruktora.

#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 Rychliński
źródło
4

Z perspektywy czasu wiele niejawnych konwersji w C ++ jest niefortunnych, jest to jedna z nich.

Jedną z opcji do rozważenia jest -Wzero-as-null-pointer-constant gcc i clang. Bądź ostrożny, ponieważ zmienia to zachowanie standardowych programów, a jeśli zostanie włączone globalnie, może mieć niezamierzone efekty.

g ++ - jak wyłączyć niejawną konwersję z 0 na typy wskaźników?

Które ostrzeżenie Clanga jest równoważne stałej Wzero-as-null-pointer-stałej z GCC?

bolov
źródło