Como evitar conversões implícitas de int (0) para ponteiro em um vetor

9

Há uma situação em que desejo coletar todos os nomes de nós de um caminho para uma chave no JSON. Considere a condição do índice de matriz "0", "1" também é permitida, mas é fácil esquecer as aspas, o que levaria a uma falha quando a desreferencia. Então, eu quero rejeitar isso. Exemplo:

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

Encontrei e tentei isso Como evito conversões implícitas em funções não construtivas? como segue:

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

Mas o compilador ainda não me entendeu.

Alguma sugestão?
Aponte qualquer uso indevido de terminologias e suposições, obrigado!

rustyhu
fonte
existe uma razão pela qual você usa em std::vector<const char*>vez de std::vector<std::string>>?
bolov 16/04
Você quer proibir nullptrtambém?
Jarod42 16/04
@bolov No começo, considero passar esses nomes de nós para uma interface de análise JSON, que usa char * de estilo C como entrada, mas isso não é limitado aqui. Eu testei, usando std :: vector <std :: string >> ainda aceita 0 ao compilar, mas trava ao executar, na minha máquina o GCC reporta "basic_string :: _ M_construct null null".
rustyhu 16/04
@ Jarod42 Sim, o que queremos é literal de string no estilo C.
rustyhu 16/04

Respostas:

9

Algo assim? É muito semelhante à solução de sobrecarga que você sugeriu, mas requer agrupar o tipo de vetor. Falha ao construir se você fornecer um literal 0porque a sobrecarga de construtor excluída foi escolhida.

#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
fonte
4

Em retrospectiva, muitas das conversões implícitas em C ++ são lamentáveis, sendo essa uma delas.

Uma opção a considerar é -Wzero-as-null-pointer-constantno gcc e no clang. Tenha cuidado, pois isso altera o comportamento dos programas padrão e, se ativado globalmente, pode ter alguns efeitos indesejados.

como desabilitar a conversão implícita de 0 para tipos de ponteiro?

Qual aviso de Clang é equivalente à constante Wzero-como-nulo-ponteiro do GCC?

Bolov
fonte