Below, I used template<int = 0> learnt from @Daniel McLaury in here.
#include <type_traits>
template<typename T>
struct A_base {
int val;
// template<int = 0> // needs it to make MSVC work
volatile T& operator=(const volatile T& a) volatile {
val = a.val;
return static_cast<volatile T&>(*this);
}
T& operator=(const volatile T& a) {
val = a.val;
return static_cast<T&>(*this);
}
};
struct A : A_base<A> {
using A_base::operator=;
A() = default;
A(const A&) = default;
template<int = 0>
A(const volatile A& a) {
*this = a;
}
};
void test(volatile A* p) {
static_assert(std::is_trivial_v<A>);
A a = *p;
*p = a;
}
Both GCC and Clang can compile the code, but MSVC failed:
error C2678: binary '=': no operator found which takes a left-hand operand of type 'volatile A' (or there is no acceptable conversion) message : could be 'A &A::operator =(const A &)' message : or
'A_base &A_base::operator =(const A_base &)' message : or
'A_base &A_base::operator =(A_base &&)' message : while trying to match the argument list '(volatile A, A)'
I need template<int = 0> on the CRTP volatile T& operator=(const volatile T& a) volatile; to make MSVC work.
I guess it's because templated code has lower priority in the overload resolution rule, is that true?
Could someone review my code, and explain which part is illegal/undefined by C++ standard?
Thank you very much.