En el siguiente código de C++ 0x me trataron de clonar un objeto mediante una función miembro clon (si existe) y volver a caer en una copia constructor:Código C++ 0x mal formado o error del compilador?
struct use_copy_ctor {};
struct prefer_clone_func : use_copy_ctor {};
template<class T>
auto clone(T const* ptr, prefer_clone_func)
-> decltype(ptr->clone())
{ return ptr->clone(); }
template<class T>
auto clone(T const* ptr, use_copy_ctor)
-> decltype(new T(*ptr))
{ return new T(*ptr); }
struct abc {
virtual ~abc() {}
virtual abc* clone() const =0;
};
struct derived : abc
{
derived* clone() const { return new derived(*this); }
};
int main()
{
derived d;
abc* p = &d;
abc* q = clone(p,prefer_clone_func());
delete q;
}
La idea es utilizar el automóvil ...-> decltype (expr) para eliminar expresiones mal formadas como parte de la deducción del argumento de la plantilla (SFINAE) y para resolver una posible ambigüedad entre ambas plantillas de funciones del clon a través de orden parcial wrt el segundo parámetro de función.
Desafortunadamente, GCC 4.5.1 no acepta este programa:
test.cpp: In function 'int main()':
test.cpp:28:39: error: cannot allocate an object of abstract type
'abc'
test.cpp:14:12: note: because the following virtual functions are
pure within 'abc':
test.cpp:16:16: note: virtual abc* abc::clone() const
test.cpp:28:39: error: cannot allocate an object of abstract type
'abc'
test.cpp:14:12: note: since type 'abc' has pure virtual functions
Ahora, la pregunta es, ¿es esto un error compilador o que era un error suponer que SFINAE aplica aquí? Agradecería una respuesta con un razonamiento sólido.
Editar: Si cambio decltype(new T(*ptr))
a T*
el código se compila a causa de resolución de sobrecarga prefiriendo la primera plantilla de función en este caso. Pero esto frustra el propósito de tener la expresión como parte de la declaración de la función. El propósito es hacer que el compilador saque la función de la resolución de sobrecarga establecida en caso de error.
Me gustaría tomar el argumento de "selección" por referencia, ya que la herencia está involucrada. No es que eso resuelva su problema ... –
@Matthieu: por referencia no es necesario para que este despacho de etiquetas funcione. La regla de resolución de sobrecarga ordenada parcial todavía se aplica. No he comprobado cómo el compilador optimiza esto, pero libstdC++ también utiliza el despacho de etiquetas sin referencias para implementar std :: advance, por ejemplo. – sellibitze
Sé que no es necesario, aún así lo haría por costumbre, supongo, para evitar el corte de objetos (no se supone que una etiqueta tenga datos/métodos ...) –