Estaba jugando con c ++ 20 consteval en GCC 10 y escribí este código
#include <optional>
#include <tuple>
#include <iostream>
template <std::size_t N, typename Predicate, typename Tuple>
consteval std::optional<std::size_t> find_if_impl(Predicate&& pred,
Tuple&& t) noexcept {
constexpr std::size_t I = std::tuple_size_v<std::decay_t<decltype(t)>> - N;
if constexpr (N == 0u) {
return std::nullopt;
} else {
return pred(std::get<I>(t))
? std::make_optional(I)
: find_if_impl<N - 1u>(std::forward<decltype(pred)>(pred),
std::forward<decltype(t)>(t));
}
}
template <typename Predicate, typename Tuple>
consteval std::optional<std::size_t> find_if(Predicate&& pred,
Tuple&& t) noexcept {
return find_if_impl<std::tuple_size_v<std::decay_t<decltype(t)>>>(
std::forward<decltype(pred)>(pred), std::forward<decltype(t)>(t));
}
constexpr auto is_integral = [](auto&& x) noexcept {
return std::is_integral_v<std::decay_t<decltype(x)>>;
};
int main() {
auto t0 = std::make_tuple(9, 1.f, 2.f);
constexpr auto i = find_if(is_integral, t0);
if constexpr(i.has_value()) {
std::cout << std::get<i.value()>(t0) << std::endl;
}
}
Se supone que funciona como el algoritmo de búsqueda STL pero en tuplas y en lugar de devolver un iterador, devuelve un índice opcional basado en un predicado de tiempo de compilación. Ahora este código se compila muy bien y se imprime
9 9
Pero si la tupla no contiene un elemento que es un tipo integral, el programa no se compila, porque i.value () todavía se llama en un opcional vacío. Ahora por qué es eso?
c++
c++20
if-constexpr
Yamahari
fuente
fuente
Respuestas:
Así es como constexpr si funciona. Si verificamos [stmt.if] / 2
énfasis mío
Entonces podemos ver que solo no evaluamos la expresión descartada si estamos en una plantilla y si la condición depende del valor.
main
no es una plantilla de función, por lo que el compilador aún verifica el cuerpo de la instrucción if para verificar que sea correctoCppreference también dice esto en su sección sobre constexpr si con:
fuente
i.value_or(0)
)