compile c++ g++ optional c++17 clang++

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 .