constexpr ise - neden atılan ifade tam olarak kontrol edilir?


14

GCC 10 c ++ 20 consteval ile uğraşıyordum ve bu kodu yazdım

#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;
    }
}

Hangi STL bulma algoritması gibi çalışacak ama tuples üzerinde ve bir yineleyici döndürmek yerine, bir derleme zamanı yüklemine dayalı isteğe bağlı bir dizin döndürür. Şimdi bu kod gayet iyi derleniyor ve yazdırılıyor

9

Ancak, demet tümleşik tipte bir öğe içermiyorsa, program derlenmez, çünkü i.value () hala boş bir isteğe bağlı olarak çağrılır. Şimdi neden böyle?



@AndyG olsa düzeltmez, değil mi? x)
Yamahari

Yanıtlar:


11

Bu nasıl çalışırsa böyledir . [Stmt.if] / 2'yi kontrol edersek

İf ifadesinin constexpr biçiminde olması durumunda, koşulun değeri, bağlamsal olarak dönüştürülmüş, bool türünde sabit bir ifade olacaktır; bu forma constexpr if ifadesi denir. Dönüştürülen koşulun değeri yanlışsa, ilk alt öğe atılan bir deyimdir, aksi takdirde varsa ikinci alt öğe, atılan bir deyimdir. Çevreleyen şablonlanmış bir varlığın ([temp.pre]) somutlaştırılması sırasında, koşul somutlaştırılmasından sonra değere bağlı değilse, atılan alt tabaka (eğer varsa) somutlaştırılmaz. [...]

benimkini vurgula

Dolayısıyla, atılan ifadeyi yalnızca bir şablondaysak ve koşul değere bağlıysa değerlendirmediğimizi görebiliriz. mainbir işlev şablonu değildir, bu nedenle if ifadesinin gövdesi derleyici tarafından hala doğru olup olmadığını kontrol eder.

Cppreference ayrıca şu durumlarda constexpr ile ilgili bölümlerinde şunları söyler:

Geçici bir varlık içinde bir constexpr if ifadesi görünürse ve örneklemeden sonra koşul değere bağlı değilse, atılan ifade, ekteki şablon başlatıldığında başlatılmaz.

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.
}

Şablonun dışında atılan bir ifade tamamen denetlenir. constexpr, #if önişleme yönergesinin yerine geçmezse:

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

bunun nedenini biliyor musun? Bu, eğer constexpr için iyi bir seçim olacaktır. Aynı zamanda çözüm, örneğin bir şekilde bir şablon içine sarmak mı?
Yamahari

@Yamahari Çünkü C ++ şablonları, olmasını istediğinizden daha fazla ve daha az yapılandırılmıştır. Ve evet, bir şablona sarın (veya yazın i.value_or(0))
Barry

2
@Yamahari Evet, çözüm kodu bir işlev şablonuna koymak olacaktır. Akıl yürütmeye gelince, nedenini bilmiyorum. Bu muhtemelen sorulması iyi bir soru olurdu.
NathanOliver

@Barry value_or (0) iyi çalışıyor, ancak demet 0 boyutunda olduğunda
Yamahari

@Yamahari Evet ... benim açımdan iyi bir öneri değil.
Barry
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.