c++ - if constexpr - 为什么完全检查丢弃的语句?

标签 c++ c++20 if-constexpr

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

#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 find 算法一样工作,但是在元组上,而不是返回迭代器,它返回一个基于编译时谓词的可选索引。现在这段代码编译得很好并打印出来

9



但是如果元组不包含一个整数类型的元素,程序就不会编译,因为 i.value() 仍然在一个空的可选项上调用。那是为什么?

最佳答案

就是这样constexpr if作品。如果我们检查 [stmt.if]/2

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 语句的主体是否正确。

Cppreference 在他们关于 constexpr 的部分中也提到了这一点:

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

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

关于c++ - if constexpr - 为什么完全检查丢弃的语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59393908/

相关文章:

polymorphism - 为什么 std::visit 不能消除模板重载的歧义

c++ - 使用 constexpr 验证构造函数中的文字参数

c++ - main 以无限循环终止线程

c++ - 错误 : invalid use of member in static member function

c++ - C++20 中是否有一个 float 包装器,可以让我默认飞船运算符?

python - 通过C++ 20协程制作python生成器

c++ - 'if constexpr branch' 不会在模板函数内的 lambda 内被丢弃

c++ - 在通用 lambda 中使用 constexpr-if 来确定参数的类型

C++ 中的 Java 模式替换(库)

c++ - 默认情况下分离构造函数定义和声明