c++11 - smart - ¿Este cambio en la resolución de sobrecarga entre Clang 3.5 y 3.6 es correcto o es un error?
smart contracts ethereum (3)
las plantillas se instancian cuando es necesario, y creo que Clang 3.6 implementó un DR donde necesitaba crear una instancia de una plantilla anterior a 3.5.
El siguiente código compila en Visual Studio 2013, gcc 4.8, clang 3.4 y clang 3.5 (Apple LLVM 6.0) pero no compila en clang 3.6 (a través de Apple LLVM 6.1)
El código es una versión simplificada de una clase complicada en nuestra base de código, que es el mínimo requerido para exhibir el problema.
La clave del problema es que la construcción de copia de TYPED_VALUE
está, en 3.6, evaluando el operador de conversión con plantilla para el tipo STRING
debido a la presencia de un constructor que acepta un STRING
; esto hace que std::is_constructible
sea evaluado, lo que lleva a que necesite la definición de STRING
(que no podemos proporcionar aquí - daría lugar a una dependencia circular en el código completo).
class STRING;
class TYPED_VALUE
{
public:
TYPED_VALUE( const TYPED_VALUE& ) = default; // explicit or implicit doesn''t make a difference
TYPED_VALUE( const STRING & ) {}
template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
operator TYPE( void ) const = delete;
};
class TYPED_STORAGE
{
public:
TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
TYPED_VALUE value;
};
El mensaje de error es
/type_traits:2329:38: error: incomplete type ''SICORE::STRING'' used in type trait expression
: public integral_constant<bool, __is_constructible(_Tp, _Args...)>
^
/main.cpp:348:99: note: in instantiation of template class ''std::__1::is_constructible<SICORE::STRING, const SICORE::STRING &>'' requested here
template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
^
/main.cpp:349:9: note: while substituting prior template arguments into non-type template parameter [with TYPE = SICORE::STRING]
operator TYPE( void ) const = delete;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
/main.cpp:355:56: note: while substituting deduced template arguments into function template ''operator type-parameter-0-0'' [with TYPE = SICORE::STRING, $1 = (no value)]
TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
^
/main.cpp:340:11: note: forward declaration of ''SICORE::STRING''
class STRING;
^
Para mí, esto parece un error en 3.6, en versiones anteriores la resolución de sobrecarga determina que el constructor de copia es el que mejor se ajusta sin tener que evaluar los argumentos de la plantilla. Traté de entender las notas de resolución de sobrecarga en el estándar, pero creo que solo confundí yo mas ;)
(Esto se puede solucionar haciendo que el constructor o el operador de conversión sean explícitos, me doy cuenta, pero ese no es el comportamiento que queremos)
¿Algún experto estándar conoce la respuesta?
El constructor de copia de TYPED_VALUE
utiliza una referencia a STRING
, no debe evaluarse.
Creo que esto es un error de clang
No he leído el nuevo estándar de C ++ durante mucho tiempo, sin embargo, no pude asegurarme de que no haya cambiado.
Creo que Clang está en lo cierto al producir este error:
La sección [temp.inst] del estándar C ++ en el párrafo 10 dice:
Si se utiliza una plantilla de función o una especialización de plantilla de función miembro de forma que implique una resolución de sobrecarga, se crea una instancia implícita de una declaración de especialización (14.8.3).
La formación de la secuencia de conversión implícita necesaria para clasificar los candidatos de sobrecarga para la llamada al constructor TYPE_VALUE requiere la creación de instancias del operador de conversión. Y el uso de un parámetro de tipo incompleto para el rasgo no forma un tipo no válido, por lo que no se trata de una falla de sustitución, es un error difícil.