Я возился с C ++ 20 Conteval в GCC 10 и написал этот код
#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;
}
}
Предполагается, что он работает как алгоритм поиска STL, но для кортежей и вместо возврата итератора возвращает необязательный индекс, основанный на предикате времени компиляции. Теперь этот код компилируется очень хорошо, и он печатает
9
Но если кортеж не содержит элемент, являющийся целочисленным типом, программа не компилируется, потому что i.value () по-прежнему вызывается для пустого необязательного параметра. Теперь, почему это?
c++
c++20
if-constexpr
Yamahari
источник
источник
Ответы:
Это просто, как работает constexpr . Если мы проверим [stmt.if] / 2
акцент мой
Таким образом, мы видим, что мы не оцениваем отброшенное выражение, только если мы находимся в шаблоне и если условие зависит от значения.
main
не является шаблоном функции, поэтому тело оператора if все еще проверяется компилятором на правильность.Cppreference также говорит об этом в своем разделе о constexpr, если с:
источник
i.value_or(0)
)