Below program has been reduced as far as possible to show the issue encountered with Visual Studio C++ compiler.
f
is some algorithm function taking on input predicate object P p
, which has user-defined copy constructor that remembers the pointer on the source object. In that constructor it is checked that source and copy objects are distinct indeed if (s == this) throw 0;
but in operator ()
the same check returns the opposite result:
struct P {
const P * s = nullptr;
constexpr P() {}
constexpr P(const P & p) : s(&p) {
if (s == this) throw 0; // never happens
}
constexpr bool operator()() const {
return s != this; // shall be always true?
}
};
constexpr bool f(P p) {
return p.s ? p() : f(p);
}
int main() {
static_assert( f(P{}) ); // fails in MSVC, where static_assert( f(P{}) == false );
}
Online demo: https://gcc.godbolt.org/z/nqYoshExj
How can one explain that the same check passes in an object's constructor, but then fails in its method?
This is certainly a bug in msvc.
msvc (but not clang nor gcc) has the same trouble with this assert:
constexpr bool g(int x, void* s = nullptr) {
if (s) return &x != s;
return g(x,&x);
}
static_assert(g(0));
Factoring out the recursion (it can only be 1 level deep) also msvc accepts the assert:
constexpr bool h(int x, void* s) {
return &x != s;
}
constexpr bool h2(int x) {
return h(x,&x);
}
static_assert(h2(0));
The same refactoring on your code has the same effect (https://gcc.godbolt.org/z/69b57TPd8).