якщо constexpr - чому відхилена операція повністю перевірена?


14

Я возився з контестуванням c ++ 20 в 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 () все ще викликається в порожній необов'язковий. Тепер чому це?



@AndyG, що не виправить це, чи не так? х)
Ямахарі

Відповіді:


11

Це так, як constexpr, якщо працює. Якщо ми перевіримо [stmt.if] / 2

Якщо оператор if має вигляд, якщо constexpr, значення умови має бути контекстуально перетвореним постійним виразом типу bool; ця форма називається constexpr if оператором. Якщо значення перетвореної умови є хибним, перший підзаголовок - це відкинутий вислів, інакше другий підзаголовок, якщо він присутній, є відхиленим твердженням. Під час створення екземпляра об'єкта, що додається до шаблону ([temp.pre]), якщо умова після його інстанціювання не залежить від значення, відкинута підстава (якщо така є) не створюється. [...]

акцент мій

Отже, ми можемо бачити, що ми не оцінюємо відкинутий вираз лише в тому випадку, якщо ми знаходимося в шаблоні і якщо умова залежить від значення. mainне є шаблоном функції, тому компілятор все-таки перевіряє тіло оператора if на правильність.

Cppreference також говорить про це у своєму розділі про constexpr, якщо з:

Якщо constexpr, якщо оператор з'являється всередині шаблонного об'єкта, і якщо умова не залежить від значення після створення екземпляра, відкинуте оператор не буде ініційовано, коли екземпляр шаблону, що вкладається.

template<typename T, typename ... Rest>
void g(T&& p, Rest&& ...rs) {
    // ... handle p
    if constexpr (sizeof...(rs) > 0)
        g(rs...); // never instantiated with an empty argument list.
}

Поза шаблоном відхилена заява повністю перевіряється. якщо constexpr не є заміною директиви попередньої обробки #if:

void f() {
    if constexpr(false) {
        int i = 0;
        int *p = i; // Error even though in discarded statement
    }
}

чи знаєте ви міркування цього? схоже, це було б добре підходити, якщо constexpr. Також таким рішенням буде, наприклад, загортати його в шаблон?
Ямахарі

@Yamahari Оскільки шаблони C ++ є більш структурованими та меншими, ніж ти хочеш. І так, загорніть його в шаблон (або напишіть як i.value_or(0))
Баррі

2
@Yamahari Так, рішенням було б ввести код у шаблон функції. Що стосується міркувань, я не знаю чому. Це, мабуть, було б гарне питання.
NathanOliver

@Barry value_or (0) працює чудово, але у випадку, коли кортеж розміром 0
Yamahari

@Yamahari Так ... не хороша пропозиція з мого боку.
Баррі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.