This code compiled by gcc trunk with std=c++17 returns 1 instead of the expected 0 since D::operator C() is called instead of the apparently better match C::C(const D&). Compiling the code with std=c++14 make this behaviour disappear and 0 is returned as expected. gcc 7.2 also has this behaviour but 6.4 do not. clang trunk also has this behaviour. Rationale for why 0 should be returned instead of 1 : (copied from the original post on stackoverflow) Tentative reading of the standard (latest draft N4687) : C c(d) is a direct-initialization which is not a copy elision ([dcl.init]/17.6.1). [dcl.init]/17.6.2 tells us that applicable constructors are enumerated and that the best one is chosen by overload resolution. [over.match.ctor] tells us that the applicable constructors are in this case all the constructors. In this case : C(), C(const C&) and C(const D&) (no move ctor). C() is clearly not viable and thus is discarded from the overload set. ([over.match.viable]) Constructors have no implicit object parameter and so C(const C&) and C(const D&) both take exactly one parameter. ([over.match.funcs]/2) We now go to [over.match.best]. Here we find that we need to determine which of these two implicit conversion sequences (ICS) is better. The ICS of C(const D&) only involves a standard conversion sequence, but the ICS of C(const C&) involves a user-defined conversion sequence. Therefore C(const D&) should be selected instead of C(const C&). See the discussion on stackoverflow: https://stackoverflow.com/questions/47110853/call-to-conversion-operator-instead-of-converting-constructor-in-c17-during-ov static int ret; struct D; struct C { C() {} C(const C&) {} C(const D&) {} }; struct D { operator C() { ret = 1; return C();} }; int main(){ D d; C c(d); return ret; } g++ -v : Using built-in specs. COLLECT_GCC=/home/bruno/software/gcc-svn-install/bin/g++ COLLECT_LTO_WRAPPER=/home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../gcc-svn/configure --prefix=/home/bruno/software/gcc-svn-install Thread model: posix gcc version 8.0.0 20171104 (experimental) (GCC) COLLECT_GCC_OPTIONS='-v' '-O0' '-g' '-std=c++17' '-Wall' '-Wextra' '-Wpedantic' '-o' 'bug_DoperatorC_CconstDref_minimal' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -D_GNU_SOURCE bug_DoperatorC_CconstDref_minimal.cpp -quiet -dumpbase bug_DoperatorC_CconstDref_minimal.cpp -mtune=generic -march=x86-64 -auxbase bug_DoperatorC_CconstDref_minimal -g -O0 -Wall -Wextra -Wpedantic -std=c++17 -version -o /tmp/cc2hfg03.s GNU C++17 (GCC) version 8.0.0 20171104 (experimental) (x86_64-pc-linux-gnu) compiled by GNU C version 8.0.0 20171104 (experimental), GMP version 6.1.2, MPFR version 3.1.6, MPC version 1.0.3, isl version none GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu" ignoring nonexistent directory "/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../../x86_64-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../../include/c++/8.0.0 /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../../include/c++/8.0.0/x86_64-pc-linux-gnu /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../../include/c++/8.0.0/backward /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/include /usr/local/include /home/bruno/software/gcc-svn-install/include /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/include-fixed /usr/include/x86_64-linux-gnu /usr/include End of search list. GNU C++17 (GCC) version 8.0.0 20171104 (experimental) (x86_64-pc-linux-gnu) compiled by GNU C version 8.0.0 20171104 (experimental), GMP version 6.1.2, MPFR version 3.1.6, MPC version 1.0.3, isl version none GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 Compiler executable checksum: a6d84215658bcb7c80db361d04a47f0c COLLECT_GCC_OPTIONS='-v' '-O0' '-g' '-std=c++17' '-Wall' '-Wextra' '-Wpedantic' '-o' 'bug_DoperatorC_CconstDref_minimal' '-shared-libgcc' '-mtune=generic' '-march=x86-64' as -v --64 -o /tmp/ccaD0Gbb.o /tmp/cc2hfg03.s GNU assembler version 2.29.1 (x86_64-linux-gnu) using BFD version (GNU Binutils for Ubuntu) 2.29.1 COMPILER_PATH=/home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/:/home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/:/home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/:/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/:/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/ LIBRARY_PATH=/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/:/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../../lib64/:/lib/x86_64-linux-gnu/:/lib/../lib64/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib64/:/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-O0' '-g' '-std=c++17' '-Wall' '-Wextra' '-Wpedantic' '-o' 'bug_DoperatorC_CconstDref_minimal' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/collect2 -plugin /home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/liblto_plugin.so -plugin-opt=/home/bruno/software/gcc-svn-install/libexec/gcc/x86_64-pc-linux-gnu/8.0.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccu9eKoi.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --eh-frame-hdr -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o bug_DoperatorC_CconstDref_minimal /usr/lib/x86_64-linux-gnu/crt1.o /usr/lib/x86_64-linux-gnu/crti.o /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/crtbegin.o -L/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0 -L/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../../../lib64 -L/lib/x86_64-linux-gnu -L/lib/../lib64 -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib64 -L/home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/../../.. /tmp/ccaD0Gbb.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /home/bruno/software/gcc-svn-install/lib/gcc/x86_64-pc-linux-gnu/8.0.0/crtend.o /usr/lib/x86_64-linux-gnu/crtn.o COLLECT_GCC_OPTIONS='-v' '-O0' '-g' '-std=c++17' '-Wall' '-Wextra' '-Wpedantic' '-o' 'bug_DoperatorC_CconstDref_minimal' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
Hmm, clang also returns 1 for -std=c++17 also. MSVC and ICC both return 0 for -std=c++latest.
This is interesting: struct D; struct C { constexpr C(int t) : t(t) {} constexpr C(const C&) {} constexpr C(const D&) {} int t = 0; }; struct D { constexpr operator C() { return C{1};} }; constexpr D d; constexpr C c(d); static_assert (c.t == 0); extern "C" void abort (void); int main(){ D d; C c(d); constexpr D d1; C c1(d1); if (c1.t != c.t) abort (); return c.t; } ---- CUT ---- I would have suspected the static_assert to hit and the program to run at runtime without any problems.
GCC changed behaviour for C++1z mode at r240889: Further P0135 refinement. * call.c (build_user_type_conversion_1): Consider conversions from a single element in an initializer-list. (build_temp): Undo early_elide_copy change. (build_over_call): Check that we don't try to copy a TARGET_EXPR in C++17 mode. Set user_conv_p here. (convert_like_real): Not here. (check_self_delegation): Split out from... (build_special_member_call): ...here. Handle C++17 copy elision. * cvt.c (early_elide_copy): Remove. (ocp_convert): Undo early_elide_copy change. * except.c (build_throw): Likewise. * init.c (expand_default_init): Likewise. * typeck.c (cp_build_modify_expr): Likewise. That refers to the guaranteed copy elision paper: https://wg21.link/p0135r1