下面的程序已尽可能减少以显示 Visual Studio C++ 编译器遇到的问题。
f
是一些接受输入谓词对象P p
的算法函数,它具有用户定义的复制构造函数,可以记住源对象上的指针。在该构造函数中,检查源对象和复制对象确实不同 if (s == this) throw 0;
但在 operator ()
中,相同的检查返回相反的结果:
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 );
}
在线演示:https://gcc.godbolt.org/z/nqYoshExj
如何解释相同的检查在对象的构造函数中传递,但在其方法中失败?
这肯定是msvc中的一个bug。
msvc(但不是 clang 或 gcc)对此断言也有同样的问题:
constexpr bool g(int x, void* s = nullptr) {
if (s) return &x != s;
return g(x,&x);
}
分解出递归(只能是 1 级深度),msvc 也接受断言:
constexpr bool h(int x, void* s) {
return &x != s;
}
constexpr bool h2(int x) {
return h(x,&x);
}
对代码进行相同的重构具有相同的效果(https://gcc.godbolt.org/z/69b57TPd8)。