Як уникнути неявних перетворень від цілого числа 0 до вказівника, як елемента вектора


11

Існує ситуація, коли я хочу зібрати всі назви вузлів шляху до ключа в JSON. Розглянемо умову індексу масиву "0", "1" також дозволено, але легко забути лапки, що призвело б до краху при відхиленні. Тому я хочу відкинути це. Приклад:

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

Я знайшов і спробував це. Як уникнути неявних перетворень на неконструюючі функції? наступним чином:

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

Але компілятор все ще мене не зрозумів.

Будь-яка пропозиція?
Будь ласка, вкажіть на будь-яке нецільове використання термінологій та припущень, дякую!


Чи є причина, чому ви використовуєте std::vector<const char*>замість std::vector<std::string>>?
болов

Ви також хочете заборонити nullptr?
Jarod42

@bolov На початку я вважаю передати ці імена вузлів інтерфейсу аналізу JSON, який використовує char * * в якості входу, але це не обмежується тут. Я протестував, використовуючи std :: vector <std :: string >> все ще приймає 0 під час компіляції, але виходить з ладу під час запуску, на моїй машині GCC повідомляє "basic_string :: _ M_construct null not valid".
rustyhu

@ Jarod42 Так, те, що потрібно, є строковим рядком у стилі C.
rustyhu

Відповіді:


10

Щось на зразок цього? Це дуже схоже на рішення, яке ви запропонували, але вимагає обгортання векторного типу. Не вдається побудувати, якщо ви надаєте буквальне значення, 0оскільки вибрано перевантаження видаленого конструктора.

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

4

З огляду на те, що багато неявних перетворень в C ++ є невдалим, і це одна з них.

Один з варіантів, який слід врахувати, - це -Wzero-as-null-pointer-constantgcc та clang. Будьте обережні, оскільки це змінює поведінку стандартних програм і, якщо це включено в усьому світі, може мати деякі непередбачувані ефекти.

g ++ - як я відключую неявну конверсію від 0 до типів вказівника?

Яке попередження Clang еквівалентно константі Wzero-as-null-pointer від GCC?


3

Мені подобається відповідь Мікель Рихліскі . Однак у Бібліотеці підтримки керівництва вже існує рішення :

gsl::not_null

Дуже рекомендую GSL. Його створили та підтримують багато експертів C ++, серед них сам Bjarne Stroustrup та Herb Sutter. А основні настанови C ++ активно інтегруються в попередження компілятора та статичні аналізатори.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.