c++ - Funciones especiales implícitas: ¿cuándo estarían mal formadas?
c++11 c++03 (2)
Si desea un ejemplo concreto, std :: pair suele ser muy fácil de copiar, pero si uno de los miembros es, digamos, un std :: unique_ptr, unique_ptr no permite copiar desde Lvalue, por lo que estaría mal formado : por lo que las operaciones de copia Lvalue por defecto de std :: pair se eliminan automáticamente.
En la Norma Internacional ISO para C ++ 11, se presenta un resumen de las diferencias entre c ++ 2003 y C ++ 2011. Una de las diferencias es:
[diff.cpp03.special]
Cambio : las funciones miembro especiales declaradas implícitamente se definen como eliminadas cuando la definición implícita no se ha formado correctamente.
Fundamento : Mejora la falla de deducción de argumentos de la plantilla.
Efecto en la característica original : un programa válido de C ++ 2003 que usa una de estas funciones miembro especiales en un contexto donde no se requiere la definición (por ejemplo, en una expresión que no se evalúa potencialmente) se descompone.
No veo en qué condición se malforman tales funciones especiales, y cómo podría romper SFINAE. Así que mi pregunta se reduce a:
- ¿Por qué ese cambio "mejora la deducción de argumentos de la plantilla" ?
- ¿Podrías dar un ejemplo?
struct NonCopyable {
NonCopyable() {}
private:
NonCopyable(const NonCopyable &);
};
struct S {
NonCopyable field;
} s;
int main() {
return sizeof S(s);
}
Aquí, NonCopyable
no se puede copiar, pero como el constructor de copia se proporciona explícitamente, no se crea un constructor de copia implícito.
Para S
, el usuario no proporciona ningún constructor de copia, por lo que se crea un constructor de copia implícito. Este constructor de copia NonCopyable
field
campo No se puede copiar, que no es copiable, por lo que el constructor de copia estaría mal formado.
En main
, se toma el tamaño de un objeto S
construido con copia. Esto requiere un constructor de copia de S
, pero en realidad no lo llama.
En C ++ 03, esto es válido. El constructor de copias estaría mal formado, pero como no se hace ninguna copia, está bien.
En C ++ 11, esto no es válido. El constructor de copia está marcado como eliminado, por lo que no se puede utilizar incluso como operando para sizeof
.
Esto permite que la metaprogramación detecte si el tipo es copiable, lo cual era imposible en C ++ 03.