installed - ¿Es este un error de clang o algo que no sé sobre C++?
where is clang installed (1)
Simplificado:
struct A {};
struct B { operator const A(); };
B b;
A a(b);
Esta es direct-initialization con el tipo de clase de destino A
, por lo que se enumeran los constructores candidatos de A
, se seleccionan todos los constructores de A (incluidos los constructores de copia y movimiento definidos implícitamente) y se comparan mediante la resolución de sobrecarga para la inicialización directa de un objeto de clase . Primero se evalúa la viability los constructores, lo que significa que se intenta construir una secuencia de conversión implícita de b
(un valor l) a su parámetro. Dado que el parámetro es una referencia ( A const&
or A&&
) debemos realizar una inicialización de referencia . Podemos inicializar una referencia A const&
desde b
ya que b
se puede convertir en un valor A const
, y A const
(el tipo de referencia de destino) y A const
(el tipo de retorno de la función de destino) son reference-compatible (ya que son el mismo tipo cv-calificado); De hecho, esta es una vinculación de referencia directa . No podemos inicializar una referencia A&&
de b
ya que A&&
tiene menos calificación de A const
que A const
. Entonces, A::A(A const&)
es el único constructor viable y se selecciona.
Se ha reportado que esto se escucha varias veces 1 2 3 pero desafortunadamente no se ha detectado.
Todos los demás compiladores principales (gcc, ICC, MSVC) compilan el código correctamente.
Curiosamente, como se explica 3 clang compila el código correctamente en el modo C ++ 03. Si obligamos a que A
sea un tipo "estilo C ++ 03" al suprimir su constructor de movimientos, el clang compilará el código resultante:
struct A { A(A const&) = default; };
struct B { operator const A(); };
B b;
A a(b);
Esto indica que quizás el Clang se está confundiendo con el constructor de movimientos. No debería, ya que el constructor de movimientos no es viable; A&& a = b;
no es válido.
Mientras miraba this pregunta, lo probé con un sonido metálico y me encontré en una situación extraña. El siguiente ejemplo:
#include <string>
class ACP
{
public:
ACP() {}
operator const std::string() const { return std::string(); }
// operator std::string() const { return std::string(); } <-- makes clang happy
};
void test()
{
const ACP acp;
auto a = (std::string)acp;
}
compila bien en coliru con gcc, pero falla con el sonido. Al menos no veo ningún problema con este ejemplo: ¿se trata de un error en clang o hay una regla que realmente explica el error de clang y que gcc está equivocado?
El error de clang se puede ver a continuación:
clang -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp:13:26: error: no viable conversion from ''const ACP'' to ''std::__cxx11::basic_string<char>''
auto a = (std::string)acp;
^~~
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:421:7: note: candidate constructor not viable: no known conversion from ''const ACP'' to ''const std::__cxx11::basic_string<char> &'' for 1st argument
basic_string(const basic_string& __str)
^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:493:7: note: candidate constructor not viable: no known conversion from ''const ACP'' to ''const char *'' for 1st argument
basic_string(const _CharT* __s, const _Alloc& __a = _Alloc())
^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:515:7: note: candidate constructor not viable: no known conversion from ''const ACP'' to ''std::__cxx11::basic_string<char> &&'' for 1st argument
basic_string(basic_string&& __str) noexcept
^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:542:7: note: candidate constructor not viable: no known conversion from ''const ACP'' to ''initializer_list<char>'' for 1st argument
basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc())
^
main.cpp:7:5: note: candidate function
operator const std::string() const { return std::string(); }
^
/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/7.1.0/../../../../include/c++/7.1.0/bits/basic_string.h:515:35: note: passing argument to parameter ''__str'' here
basic_string(basic_string&& __str) noexcept
^
1 error generated.
Sin embargo, no puedo ver por qué el compilador no pudo usar el ctor de copia desde std::string
.