$ cat test.cpp template<class T> struct SP { SP(); SP(T*); void operator=(T*); operator T*(); }; struct B{}; struct D:B{}; void f() { SP<D> d; SP<B> b = d; } $ cl -c test.cpp Microsoft (R) C/C++ Optimizing Compiler Version 17.00.61030 for x86 Copyright (C) Microsoft Corporation. All rights reserved. test.cpp $ clang-cl -c test.cpp test.cpp(14,9) : error: no viable conversion from 'SP<D>' to 'SP<B>' SP<B> b = d; ^ ~ test.cpp(2,8) : note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'SP<D>' to 'const SP<B> &' for 1st argument struct SP { ^ test.cpp(2,8) : note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'SP<D>' to 'SP<B> &&' for 1st argument struct SP { ^ test.cpp(4,3) : note: candidate constructor not viable: no known conversion from 'SP<D>' to 'B *' for 1st argument SP(T*); ^ test.cpp(6,3) : note: candidate function operator T*(); ^ 1 error generated. It seems like MSVC first invokes SP::operator T*() and then invokes the ctor taking the T* from it, which requires another implicit conversion from D* to B*. I don't think this is valid C++, but we may want to support it for compat with MSVC.
> It seems like MSVC first invokes SP::operator T*() and then invokes the ctor taking the T* from it, which requires another implicit conversion from D* to B*. I don't think this is valid C++, but we may want to support it for compat with MSVC. I'm surprised that they allow that (it seems to compile with the 14 CTP too). Unless we really can't avoid it, I don't think we should support this. For smart pointers, I think the common thing to do is to provide templates for converting copy constructors and assignment operators, something like: template <typename T> SP { ... template <typename U> SP(SP<U> other) { ... } template <typename U> void operator=(SP<U> other); } I'll mark this wontfix for now.
Agreed on the wontfix, FWIW I fixed this issue on our side, just filed this so that we have a record of the issue!