Eu tenho um código usando SFINAE "clássico".
template<class M> auto power(M const& elem) -> decltype(std::norm(elem)) { return std::norm(elem); }
template<class M, class = std::enable_if_t<(M::rank::value >= 1)>>
auto power(M const& array) {
return accumulate(begin(array), end(array), 0.0, [](auto const& alpha, auto const& omega) { return alpha + power(omega); });
}
Esta é uma função de "poder" recursiva (através de dimensões ou classificações) que, em última análise, fornece a soma dos quadrados dos elementos calculando o poder dos subelementos de dimensão inferior.
O C++ moderno incentiva o uso if constexpr
para evitar o uso de SFINAE, como abaixo.
template<class M>
auto power(M const& array) {
if constexpr(M::rank::value >= 1) {
return accumulate(begin(array), end(array), 0.0, [](auto const& alpha, auto const& omega) { return alpha + power(omega); });
} else {
return std::norm(array);
}
}
O problema é que parece que a expressão no if constexpr
tem que ser uma expressão válida em primeiro lugar. Os elementos não possuem um tipo de membro chamado rank
, portanto há um erro de compilação.
Existe algum truque para fazer o if constexpr
predicado se a expressão for inválida?
C++20 e mais recente:
Há também uma opção menos detalhada:
Mas o último é pior, porque causa um erro grave se a condição não for conhecida em tempo de compilação, enquanto o primeiro apenas retorna falso.
O primeiro é usado na biblioteca padrão (veja também Em um requisito aninhado, por que usar
requires bool_constant<X>::value;
em vez derequires X;
? ).C++17:
Use o idioma de detecção:
Então: