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 std::string(0)
construtor para inserir o método, o que gera o mesmo problema (pesquise no google o erro acima) sem uma boa razão.
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.
c++
string
std
implicit-conversion
kabanus
fonte
fonte
operator[]()
aceita umint
argumento e não o defina.Respostas:
O motivo
std::string(0)
é válido, devido a0
ser uma constante de ponteiro nulo. Portanto, 0 corresponde ao construtor de cadeias usando um ponteiro. Em seguida, o código entra em conflito com a pré-condição para a qual não se pode passar um ponteiro nulostd::string
.Somente literal
0
seria interpretado como uma constante de ponteiro nulo, se fosse um valor de tempo de execução em um caso,int
você não teria esse problema (porque a resolução de sobrecarga estaria procurando umaint
conversão). Nem literalmente é1
um problema, porque1
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:
std::nullptr_t
é do tipo denullptr
. E ele irá corresponder qualquer constante ponteiro nulo, seja ele0
,0ULL
ounullptr
. E, como a função é excluída, isso causará um erro de tempo de compilação durante a resolução de sobrecarga.fonte
std::string
o construtor não é permitido pelo padrão C ++. É um comportamento indefinido, para que o MSVC possa fazer o que quiser (como lançar uma exceção).Uma opção é declarar que uma
private
sobrecargaoperator[]()
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 as
void operator[](std::nullptr_t) = delete
que são válidas a partir do C ++ 11.Tornar
operator[]()
umprivate
membro causará um erro diagnosticável no seu exemploohNo[0]
, a menos que essa expressão seja usada por uma função de membro oufriend
da classe.Se essa expressão for usada em 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).fonte