c++ - Impedir que a função pegue const std:: string e aceite 0




implicit-conversion (2)

O motivo std::string(0) é válido, porque 0 é uma constante de ponteiro nulo. Portanto, corresponde ao construtor que está usando um ponteiro. Em seguida, ele entra em conflito com a pré-condição de que não se pode passar um ponteiro nulo para std::string . Somente 0 literal seria interpretado como uma constante de ponteiro nulo, se fosse um valor de tempo de execução em um int você não teria esse problema (porque a resolução de sobrecarga procuraria uma conversão de int ). O literal 1 também não é um problema, porque 1 não é uma constante de ponteiro nulo.

Como é um problema de tempo de compilação (valores inválidos literais), você pode detectá-lo no momento da compilação. Adicione uma sobrecarga deste formulário:

void operator[](std::nullptr_t) = delete;

std::nullptr_t é o tipo de nullptr . E corresponderá a qualquer constante de ponteiro nulo, seja 0 , 0ULL ou nullptr . E, como a função é excluída, isso causará um erro de tempo de compilação durante a resolução de sobrecarga.

Vale mais que mil palavras:

#include<string>
#include<iostream>

class SayWhat {
    public:
    SayWhat& operator[](const std::string& s) {
        std::cout<<"here\n"; // To make sure we fail on function entry
        std::cout<<s<<"\n";
        return *this;
    }
};

int main() {
    SayWhat ohNo;
    // ohNo[1]; // Does not compile. Logic prevails.
    ohNo[0]; // you didn't! this compiles.
    return 0;
}

O compilador não está reclamando ao passar o número 0 para o operador de colchete que aceita uma string. Em vez disso, isso compila e falha antes da entrada no método com:

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

Para referência:

> g++ -std=c++17 -O3 -Wall -Werror -pedantic test.cpp -o test && ./test
> g++ --version
gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)

Meu palpite

O compilador está implicitamente usando o construtor std::string(0) para inserir o método, que gera o mesmo problema (pesquise no google o erro acima) sem um bom motivo.

Pergunta, questão

Existe alguma maneira de corrigir isso no lado da classe, para que o usuário da API não sinta isso e o erro seja detectado no momento da compilação?

Ou seja, adicionando uma sobrecarga

void operator[](size_t t) {
    throw std::runtime_error("don't");
}

não é uma boa solução.


Uma opção é declarar uma sobrecarga private do operator[]() que aceita um argumento integral e não o define.

Esta opção funcionará com todos os padrões C ++ (1998 em diante), ao contrário de opções como void operator[](std::nullptr_t) = delete que são válidos a partir do C ++ 11.

Tornar o operator[]() um membro private causará um erro diagnosticável no seu exemplo ohNo[0] , a menos que essa expressão seja usada por uma função de membro ou friend da classe.

Se essa expressão for usada a partir de uma função membro ou friend da classe, o código será compilado, mas - como a função não está definida - geralmente a compilação falhará (por exemplo, um erro do vinculador devido a uma função indefinida).





implicit-conversion