首页 > 解决方案 > 有没有办法递归使用类模板参数推导指南?(图灵完备)

问题描述

我正在使用 Class Template Deduction Guide 并尝试递归使用它。但我无法获得以下代码进行编译

#include <type_traits>

template<int N>
using int_const = std::integral_constant<int,N>;

template<int N>
struct Foo{
    constexpr static int value = N;

    template<int C>
    constexpr Foo(int_const<C>){};
};

Foo(int_const<0>) -> Foo<1>;

template<int N>
Foo(int_const<N>) -> Foo<N*(Foo{int_const<N-1>{}}.value)>;

int main(){
    return Foo{int_const<5>{}}.value;
}

这是错误:

<source>: In substitution of 'template<int N> Foo(int_const<N>)-> Foo<(N * >     Foo{std::integral_constant<int, (N - 1)>{}}.value)> [with int N = -894]':
<source>:17:51:   recursively required by substitution of 'template<int N> Foo(int_const<N>)-> Foo<(N * Foo{std::integral_constant<int, (N - 1)>{}}.value)> [with int N = 4]'
<source>:17:51:   required by substitution of 'template<int N> Foo(int_const<N>)-> Foo<(N * Foo{std::integral_constant<int, (N - 1)>{}}.value)> [with int N = 5]'
<source>:20:30:   required from here
<source>:17:1: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
 Foo(int_const<N>) -> Foo<N*(Foo{int_const<N-1>{}}.value)>;
 ^~~

编译终止。

标签: c++c++17template-argument-deduction

解决方案


您需要一个帮助模板:

template<int N>
struct foo_helper
{ static constexpr int value = N * Foo{int_const<N-1>{}}.value; };
template<>
struct foo_helper<0>
{ static constexpr int value = 1; };

有了这个(也是唯一的)扣除指南:

template<int C>
Foo(int_const<C>)
-> Foo<foo_helper<C>::value>
;

Foo{int_const<5>{}}.value正确评估为 120 的现场演示。

为什么会这样?

因为有了下面的扣分指南

template<int N>
Foo(int_const<N>) -> Foo<N*(Foo{int_const<N-1>{}}.value)>;

当 CTAD 启动时,会考虑所有指南;即使您提供了更专业的指南 ( Foo<0>),此递归指南也明确专门化并Foo{int_const<N-1>{}}最终专门用于N=0,因此是无限递归。

间接层的引入foo_helper打破了这种无限递归:您可以专门化一个类,而不是演绎指南。


推荐阅读