2011-01-28 12 views
6

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.

+0

Me gustaría tomar el argumento de "selección" por referencia, ya que la herencia está involucrada. No es que eso resuelva su problema ... –

+0

@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

+0

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

Respuesta

1

Creo que me convencí a mí mismo de que esto es en realidad un error del compilador y archivé un report. Veamos qué pasa. Como una solución decltype(new T(*ptr)) se puede reemplazar por T*. La única diferencia es que la plantilla de función seguirá siendo parte del conjunto de resolución de sobrecarga, que no es un gran problema en este caso.

Editar: Btw, me dijeron que clang ++ acepta el código anterior.

1

Tuve un problema muy similar con MSVC, y resultó que el compilador no reconocería mis tipos de devolución de covariante en la función virtual. Intente cambiar la definición de clon de derived para devolver un abc.

+0

Esto no ayuda. 'derived' no es abstracto. Incluso creo un objeto de tipo 'derived' en la función principal. – sellibitze

Cuestiones relacionadas