如果constexpr-为什么要完全检查废弃的语句? [英] if constexpr - why is discarded statement fully checked?

查看:124
本文介绍了如果constexpr-为什么要完全检查废弃的语句?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在GCC 10中搞砸了c ++ 20 consteval并编写了这段代码

I was messing around with c++20 consteval in GCC 10 and wrote this code

#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查找算法那样工作,但是在元组上,而不是返回迭代器,它基于编译时间谓词返回可选索引.现在,这段代码可以很好地编译并打印出

Which is supposed to work like the STL find algorithm but on tuples and instead of returning an iterator, it returns an optional index based on a compile time predicate. Now this code compiles just fine and it prints out

9

但是,如果元组不包含整数类型的元素,则程序不会编译,因为i.value()仍在空的可选字段上调用.现在为什么呢?

But if the tuple does not contain an element that's an integral type, the program doesn't compile, because the i.value() is still called on an empty optional. Now why is that?

推荐答案

[stmt.if]/2

This is just how constexpr if works. If we check [stmt.if]/2

如果if语句的形式为if constexpr,则条件的值应为上下文转换为bool类型的常量表达式;这种形式称为constexpr if语句.如果转换后的条件的值为false,则第一个子语句为废弃的语句,否则,第二个子语句(如果存在)为废弃的语句. 在实例化封闭的模板实体([temp.pre])期间,如果条件在实例化后不依赖于值,则不会实例化丢弃的子语句(如果有). [... ]

If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool; this form is called a constexpr if statement. If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity ([temp.pre]), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.[...]

强调我的

因此,我们可以看到,只有在模板中并且条件与值相关时,我们才不对舍弃的表达式求值. main不是函数模板,因此编译器仍会检查if语句的主体是否正确.

So we can see that we only do not evaluate the discarded expression if we are in a template and if the condition is value-dependent. main is not a function template so the body of the if statement is still checked by the compiler for correctness.

Cppreference在以下有关constexpr的部分中也说了这一点:

Cppreference also says this in their section about constexpr if with:

如果constexpr if语句出现在模板实体内部,并且实例化后条件不依赖于值,则在实例化封闭模板时不会实例化丢弃的语句.

If a constexpr if statement appears inside a templated entity, and if condition is not value-dependent after instantiation, the discarded statement is not instantiated when the enclosing template is instantiated .

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预处理指令:

Outside a template, a discarded statement is fully checked. if constexpr is not a substitute for the #if preprocessing directive:

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

这篇关于如果constexpr-为什么要完全检查废弃的语句?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆