【问题标题】:C++ Template: Kind of like infinite recursion but not reallyC++ 模板:有点像无限递归,但不是真的
【发布时间】:2021-12-22 19:47:50
【问题描述】:

我有以下代码:

#include <cstdint>

template <uint32_t test_value, uint32_t ...Vn>
struct is_prime_tmpl;

template <uint32_t test_value>
struct is_prime_tmpl<test_value> {
    static constexpr bool value = true;
};

template <uint32_t test_value, uint32_t V1, uint32_t ...Vn>
struct is_prime_tmpl<test_value, V1, Vn...> {
    static constexpr bool value = (test_value % V1 != 0) && is_prime_tmpl<test_value, Vn...>::value;
};

template <uint32_t ...Vn>
struct prime {};

template <uint32_t max_target, uint32_t test_value, class PrimeList>
struct generate_prime_helper_tmpl;

template <uint32_t max_target, uint32_t test_value, uint32_t ...Vn>
struct generate_prime_helper_tmpl<max_target, test_value, prime<Vn...>> {
    static constexpr auto result = test_value <= max_target ? 
            (is_prime_tmpl<test_value, Vn...>::value ? 
                generate_prime_helper_tmpl<max_target, test_value + 1, prime<Vn..., test_value>>::result :                  generate_prime_helper_tmpl<max_target, test_value + 1, prime<Vn...>>::result) :
            prime<Vn...>();
};

int main() {
    static_assert(is_prime_tmpl<2>::value);
    static_assert(std::is_same_v<generate_prime_helper_tmpl<2, 2, prime<>>::result, prime<2>);
}

代码试图生成一个素数序列。但它无法在我的本地机器上用 g++10 编译。编译器不会发出任何警告或错误。它只是永远编译。

似乎递归以某种方式被破坏了。但我看不到它。比起实际的解决方案,我更感兴趣的是哪里出了问题。

知道出了什么问题吗?

【问题讨论】:

    标签: c++ templates c++17 variadic-templates template-meta-programming


    【解决方案1】:

    您的三元运算符确实停止递归,这使您的代码陷入无限递归。当参数不满足条件时,您应该使用if constexpr 来防止递归。

    类似这样的:

    template <uint32_t max_target, uint32_t test_value, uint32_t ...Vn>
    struct generate_prime_helper_tmpl<max_target, test_value, prime<Vn...>> {
      static constexpr auto result = [] {
        if constexpr (test_value <= max_target) {
          if constexpr (is_prime_tmpl<test_value, Vn...>::value)
            return generate_prime_helper_tmpl<max_target, test_value + 1, prime<Vn..., test_value>>::result;
          else
            return generate_prime_helper_tmpl<max_target, test_value + 1, prime<Vn...>>::result;
        }
        else
          return prime<Vn...>();
      }();
    };
    

    Demo.

    【讨论】:

    • 感谢您提供有趣的解决方案。我认为通过将result 声明为constexpr,它将强制编译器在编译时评估整个表达式,但似乎编译器试图在不评估三元运算的情况下扩展代码......
    • @HCSF - 当然可以。评估表达式需要两个格式正确的操作数,即使一个没有使用。
    • @StoryTeller-UnslanderMonica 所以你说的是因为当编译器看到三元运算符时,它不会先尝试评估条件表达式,但编译器会先尝试评估两个操作数,所以它变成无限递归,用if constexpr,编译器会先计算条件表达式?
    • @HCSF - 不。编译器不评估条件。这种递归发生在评估之前。条件被解析,它的两个操作数必须是一些可以出现在条件中的实体。所以编译器别无选择,只能实例化它们以查看它们是否甚至是有效的操作数。冲洗并重复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    • 2021-01-16
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    相关资源
    最近更新 更多