c++ - compile - llvm 3.7 0
Diferentes resultados en Clang y GCC al convertir a std:: opcional<T> (1)
Dado el siguiente código:
#include <iostream>
#include <optional>
struct foo
{
explicit operator std::optional<int>() {
return std::optional<int>( 1 );
}
explicit operator int() {
return 0;
}
};
int main()
{
foo my_foo;
std::optional<int> my_opt( my_foo );
std::cout << "value: " << my_opt.value() << std::endl;
}
gcc 7.2.0 escribe el value: 1
.
MSVC 2017 (15.3) y clang 4.0.0 sin embargo, escriba el value: 0
.
¿Cuál es correcto de acuerdo con el estándar C ++?
Como se trata de una inicialización directa, enumeramos los constructores y simplemente seleccionamos el mejor. Los constructores relevantes para std::optional
son:
constexpr optional( const optional& other ); // (2)
constexpr optional( optional&& other ) noexcept(/* see below */); // (3)
template < class U = value_type >
/* EXPLICIT */ constexpr optional( U&& value ); // (8), with U = foo&
Ambos son viables ( (8)
solo participa en la resolución de sobrecarga si int
es construible desde foo&
y foo
no es std::in_place_t
ni std::optional<int>
, todos los cuales se mantienen), pero (8)
es una coincidencia exacta mientras que (2)
y (3)
requieren una conversión definida por el usuario, por lo que se debe preferir. gcc está mal aquí.
Sin embargo, gcc tampoco invoca (3)
. Simplemente inicializa my_opt
directamente del resultado de convertir my_foo
a un optional<int>
. Este programa con gcc 7.2 imprime 3
pero ninguno de 1a
, 1b
o 2
:
#include <iostream>
template <class T>
struct opt {
opt() { }
opt(opt const& ) { std::cout << "1a/n"; }
opt(opt&& ) { std::cout << "1b/n"; }
template <class U>
opt(U&& ) { std::cout << "2/n"; }
};
struct foo
{
explicit operator opt<int>() { std::cout << "3/n"; return {}; }
};
int main()
{
opt<int> o(foo{});
}
No creo que sea una ruta permisible. Archivé 81952 .