c++visual-c++c++17constexprcopy-constructor

Object's state changes after its construction and before a member function call


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?


Solution

  • 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));
    

    Live Demo

    The same refactoring on your code has the same effect (https://gcc.godbolt.org/z/69b57TPd8).