我正在使用“类模板推导指南”,并尝试递归使用。但是我无法获取以下代码进行编译
#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)>; ^~~
编译终止。
答案 0 :(得分:0)
您需要一个辅助模板:
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>
;
Live demo和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
打破了这种无限递归:您可以专门设计一个类,而不是推论指南。
答案 1 :(得分:0)
以下代码有效:
#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>){};
};
template<int N>
constexpr auto previous_foo(){
if constexpr (N<=0){
return 1;
}
else {
return decltype(Foo{int_const<N-1>{}})::value;
}
}
template<int N>
Foo(int_const<N>) -> Foo<(N>0)?N*previous_foo<N>():1>;
int main(){
return Foo{int_const<5>{}}.value;
}