Eu estava brincando com c ++ 20 consteval no GCC 10 e escrevi 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;
}
}
Que deve funcionar como o algoritmo de localização STL, mas em tuplas e, em vez de retornar um iterador, ele retorna um índice opcional com base em um predicado de tempo de compilação. Agora esse código compila muito bem e é impresso
9
Mas se a tupla não contiver um elemento de tipo integral, o programa não será compilado, porque o i.value () ainda é chamado em um opcional vazio. Agora, por que isso?
c++
c++20
if-constexpr
Yamahari
fonte
fonte
Respostas:
É assim que o constexpr funciona. Se verificarmos [stmt.if] / 2
ênfase minha
Portanto, podemos ver que apenas não avaliamos a expressão descartada se estivermos em um modelo e se a condição for dependente de valor.
main
não é um modelo de função, portanto, o corpo da instrução if ainda é verificado pelo compilador quanto à correção.O Cppreference também diz isso em sua seção sobre constexpr se com:
fonte
i.value_or(0)
)