c++ - plus - ¿Los constructores eliminados son "accesibles"?
c++ website (2)
A partir de la segunda cita de la pregunta, diría que la accesibilidad no se ve afectada por delete
dness, y que la primera cita en realidad no cubre en absoluto el caso de que tal constructor pueda ser delete
d.
En su lugar, este escenario está cubierto por una especie de requisito "catch-all" en la definición de delete
:
[C++11: 8.4.3/2]:
un programa que hace referencia a una función eliminada de manera implícita o explícita, que no sea para declararla, está mal formado. [Nota: Esto incluye llamar a la función implícita o explícitamente y formar un puntero o puntero a miembro para la función. Se aplica incluso para referencias en expresiones que no son potencialmente evaluadas. Si una función está sobrecargada, se hace referencia solo si la función se selecciona por resolución de sobrecarga. "Nota final"
Por lo tanto, cppreference.com probablemente podría hacer con una nota de que hay un criterio adicional que se aplica al rasgo is_move_constructible
, que simplemente si el constructor de movimientos es accesible. Y hay un problema adicional aquí, que es que MoveConstructible
puede ser satisfecho con CopyConstructible
† , por lo que incluso el constructor de movimientos por sí solo no es estrictamente necesario.
Sin embargo, todo esto plantea otro punto interesante, sin embargo, es que cualquier posible implementación de is_move_constructible
debe "referirse" al constructor de movimientos eliminados, lo que hace que el programa no is_move_constructible
como se indica en la cita anterior. Aun así, supongo que con los trucos de SFINAE, una implementación puede evitar que se forme mal.
† "Un tipo sin ctor de movimiento en absoluto pero con un copia-ctor es movible construible (construible a partir de un valor)." - DyP
Una respuesta eliminada en esta pregunta sobre un constructor de movimientos eliminado cita a cppreference.com y dice que el rasgo is_move_constructible
debe tener éxito siempre que un constructor de movimientos sea "accesible", incluso si no es "utilizable".
De hecho, el estándar requiere que la construcción de movimientos del tipo de argumento esté bien formada, por lo que la respuesta no fue del todo correcta.
Ahora, el estándar usa repetidamente el término "accesible" en relación con los constructores que se refieren a la constructibilidad real. Por ejemplo:
[C++11 8.5/6]:
Para inicializar por defecto un objeto de tipoT
significa:
- si
T
es una clase de clase (posiblemente calificada para cv ) (Cláusula 9), se llama al constructor predeterminado paraT
(y la inicialización es incorrecta siT
no tiene un constructor por defecto accesible );- si
T
es un tipo de matriz, cada elemento se inicializa por defecto ;- De lo contrario, no se realiza ninguna inicialización.
Si un programa solicita la inicialización predeterminada de un objeto de un tipo
T
constante,T
será un tipo de clase con un constructor predeterminado proporcionado por el usuario.
Sin embargo, no puedo encontrar en ninguna parte del estándar que indique categóricamente si un constructor de delete
explícita, explícitamente definido es "accesible" o no.
Una cita diferente [no normativa] parece sugerir que la delete
del acceso y la accesibilidad son ortogonales:
[C++11: 12.2/1]:
[..] [Nota: incluso si no hay una llamada al destructor o al constructor de copia / movimiento, todas las restricciones semánticas, como la accesibilidad (Cláusula 11) y si la función es suprimido (8.4.3), se cumplirá. [..]
- ¿Me he perdido un pasaje?
- Si no, ¿debería corregirse la página cppreference.com? ¿Puedes sugerir una mejor redacción?
- ¿Debería el estándar ser más claro al respecto?
No quiero abordar lo que dice el sitio web cppreference, pero en lo que respecta a la norma, la constructibilidad no se define en términos de "constructores accesibles". Más bien, la definición primaria es la de is_constructible
, que es (C ++ 11, 20.9.4.3/6):
is_constructible<T, Args...>
se cumplirá si y solo si la siguiente definición de variable estaría bien formada para alguna variable inventada
t
:
T t(create<Args>()...);
La verificación de acceso se realiza como en un contexto no relacionado con
T
y cualquiera de losArgs
. Solo se considera la validez del contexto inmediato de la inicialización de la variable.
Entonces, la buena forma de la expresión hipotética en la última línea de código es la característica definitoria de los rasgos de constructibilidad. Y eso funciona de la mano con la cláusula que dice que el uso de una función eliminada lleva a un programa mal formado.