O programa abaixo foi reduzido ao máximo para mostrar o problema encontrado com o compilador Visual Studio C++.
f
é alguma função de algoritmo que assume o objeto predicado de entrada P p
, que possui um construtor de cópia definido pelo usuário que lembra o ponteiro no objeto de origem. Nesse construtor é verificado se os objetos fonte e cópia são realmente distintos, if (s == this) throw 0;
mas na operator ()
mesma verificação retorna o resultado oposto:
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 );
}
Demonstração online: https://gcc.godbolt.org/z/nqYoshExj
Como explicar que a mesma verificação passa no construtor de um objeto, mas falha em seu método?
Este é certamente um bug no msvc.
msvc (mas não clang nem gcc) tem o mesmo problema com esta afirmação:
Fatorando a recursão (ela só pode ter 1 nível de profundidade), o msvc também aceita a afirmação:
Demonstração ao vivo
A mesma refatoração em seu código tem o mesmo efeito ( https://gcc.godbolt.org/z/69b57TPd8 ).