c++ string std implicit-conversion

c++ - Evite que la función tome const std:: string & de aceptar 0



implicit-conversion (2)

Vale más que mil palabras:

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

El compilador no se queja al pasar el número 0 al operador de soporte que acepta una cadena. En cambio, esto se compila y falla antes de ingresar al método con:

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

Para referencia:

> 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)

Mi conjetura

El compilador está usando implícitamente el constructor std::string(0) para ingresar el método, lo que genera el mismo problema (google el error anterior) sin ninguna buena razón.

Pregunta

¿Hay alguna forma de arreglar esto en el lado de la clase, para que el usuario de la API no sienta esto y el error se detecte en el momento de la compilación?

Es decir, agregar una sobrecarga

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

No es una buena solución.


La razón por la cual std::string(0) es válida, se debe a que 0 es una constante de puntero nulo. Entonces coincide con el constructor tomando un puntero. Luego, entra en conflicto con la condición previa de que no se puede pasar un puntero nulo a std::string . Solo el 0 literal se interpretaría como una constante de puntero nulo, si fuera un valor de tiempo de ejecución en un int no tendría este problema (porque entonces la resolución de sobrecarga buscaría una conversión int ). El literal 1 tampoco es un problema, porque 1 no es una constante de puntero nulo.

Como se trata de un problema de tiempo de compilación (valores no válidos literales), puede detectarlo en tiempo de compilación. Agregue una sobrecarga de este formulario:

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

std::nullptr_t es el tipo de nullptr . Y coincidirá con cualquier constante de puntero nulo, ya sea 0 , 0ULL o nullptr . Y dado que la función se elimina, provocará un error de tiempo de compilación durante la resolución de sobrecarga.


Una opción es declarar una sobrecarga private del operator[]() que acepta un argumento integral y no lo define.

Esta opción funcionará con todos los estándares de C ++ (1998 en adelante), a diferencia de opciones como void operator[](std::nullptr_t) = delete que son válidas desde C ++ 11.

Hacer que el operator[]() un miembro private causará un error diagnosticable en su ejemplo ohNo[0] , a menos que esa expresión sea utilizada por una función miembro o un friend de la clase.

Si esa expresión se usa desde una función miembro o friend de la clase, el código se compilará pero, dado que la función no está definida, generalmente la compilación fallará (por ejemplo, un error de enlace debido a una función indefinida).