如何管理具有递归函数调用的模板类中的数组(以数组的长度作为参数)?
Posted
技术标签:
【中文标题】如何管理具有递归函数调用的模板类中的数组(以数组的长度作为参数)?【英文标题】:How do you manage an array in a template class (with the length of the array as a parameter) that has recursive function calls? 【发布时间】:2022-01-23 21:02:20 【问题描述】:这是我的部分代码的要点:
#include <iostream>
using namespace std;
class Exception
;
template <int row_length>
class IntContainer
private:
int mem[row_length];
public:
IntContainer()
for (int i = 0; i < row_length; i++) mem[i] = i;
~IntContainer()
int get_det()
if (row_length == 2) return mem[0] + mem[1];
else if (row_length == 1) return mem[0];
else return get_cofactor();
int get_cofactor()
if (row_length == 1) throw Exception();
IntContainer<row_length - 1> temp;
return temp.get_det();
;
int main()
IntContainer<5> ic1;
cout << ic1.get_det();
用g++编译,出现如下错误:
error: size '18446744073709551615' of array exceeds maximum object size '9223372036854775807'
11| int mem[row_length];
我应该怎么做才能在没有编译错误的情况下管理数组(我在函数中正确处理)?
【问题讨论】:
您需要为row_length
of 1 专门化模板,以确保它不会尝试递归创建数组大小为 0 或更小的实例
你如何专门化 row_length
参数?
【参考方案1】:
为什么会这样
即使row_length
为 1 或 2 时不会调用 get_cofactor()
,它仍然会被定义。
这反过来又为row_length
定义了IntContainer
,大小为1、0,最后是-1(环绕到MAX_INT
)。
您可以在编译器资源管理器的 gcc 11.2 的 diagnostic output 中看到这一点:
<source>: In instantiation of 'class IntContainer<-1>':
<source>:30:38: required from 'int IntContainer<row_length>::get_cofactor() [with int row_length = 0]'
<source>:24:21: required from 'int IntContainer<row_length>::get_det() [with int row_length = 0]'
<source>:31:28: required from 'int IntContainer<row_length>::get_cofactor() [with int row_length = 1]'
<source>:24:21: required from 'int IntContainer<row_length>::get_det() [with int row_length = 1]'
<source>:31:28: required from 'int IntContainer<row_length>::get_cofactor() [with int row_length = 2]'
<source>:24:21: [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
<source>:24:21: required from 'int IntContainer<row_length>::get_det() [with int row_length = 3]'
<source>:31:28: required from 'int IntContainer<row_length>::get_cofactor() [with int row_length = 4]'
<source>:24:21: required from 'int IntContainer<row_length>::get_det() [with int row_length = 4]'
<source>:31:28: required from 'int IntContainer<row_length>::get_cofactor() [with int row_length = 5]'
<source>:24:21: required from 'int IntContainer<row_length>::get_det() [with int row_length = 5]'
<source>:39:24: required from here
<source>:11:9: error: size '18446744073709551615' of array exceeds maximum object size '9223372036854775807'
11 | int mem[row_length];
| ^~~
Compiler returned: 1
C++17if constexpr
解决方案
如果您使用的是 C++17,那么一种解决方案是将 get_det()
中的条件句转换为 if constexpr
语句
这会抑制对get_cofactor
的调用,应该...抑制它被定义。那时我对模板很模糊。如果这不是可移植的,它可能需要模板专业化。
#include <iostream>
using namespace std;
class Exception
;
template <int row_length>
class IntContainer
private:
int mem[row_length];
public:
IntContainer()
for (int i = 0; i < row_length; i++) mem[i] = i;
~IntContainer()
int get_det()
if constexpr (row_length == 2) return mem[0] + mem[1];
else if constexpr (row_length == 1) return mem[0];
else return get_cofactor();
int get_cofactor()
if constexpr (row_length == 1)
throw Exception();
return 0;
else
IntContainer<row_length - 1> temp;
return temp.get_det();
;
int main()
IntContainer<5> ic1;
cout << ic1.get_det();
特殊递归退出案例的模板特化
FWIW 我认为重写它以使用模板专业化可能会更简洁:
#include <iostream>
using namespace std;
class Exception
;
template <int row_length>
class IntContainer
private:
int mem[row_length];
public:
IntContainer()
for (int i = 0; i < row_length; i++) mem[i] = i;
~IntContainer()
int get_det()
std::cout << "Entered get_det() row_length = " << row_length << '\n';
return get_cofactor();
int get_cofactor()
std::cout << "Entered get_cofactor() row_length = " << row_length << '\n';
IntContainer<row_length - 1> temp;
return temp.get_det();
;
template <>
int IntContainer<1>::get_det()
std::cout << "Entered specialized get_det() row_length = " << 1 << '\n';
return mem[0];
template <>
int IntContainer<1>::get_cofactor()
std::cout << "Entered specialized get_cofactor() row_length = " << 1 << '\n';
// throw Exception();
return 0;
template <>
int IntContainer<2>::get_det()
std::cout << "Entered specialized get_det() row_length = " << 2 << '\n';
return mem[0] + mem[1];
int main()
IntContainer<5> ic1;
cout << ic1.get_det() << '\n';
IntContainer<1>.get_cofactor();
以上输出
Entered get_det() row_length = 5
Entered get_cofactor() row_length = 5
Entered get_det() row_length = 4
Entered get_cofactor() row_length = 4
Entered get_det() row_length = 3
Entered get_cofactor() row_length = 3
Entered specialized get_det() row_length = 2
1
Entered specialized get_cofactor() row_length = 1
【讨论】:
可能值得注意的是,if constexpr
需要 C++17,有些人可能还不能使用。在这种情况下,模板专业化是解决问题的“旧方法”
您还应该在get_cofactor
中使用if constexpr
,因为这是递归实际发生的地方。
template<> int IntContainer<1>::get_det()
有效吗?我认为您必须专门化整个封闭类模板,而不能只专门化成员函数的定义。
@NathanPierson 我运行它。不确定它是否完整。我可能会遗漏一些边缘情况。我知道您不能对课程进行部分模板专业化,但这可以按书面方式进行。如果你弄清楚了,请告诉我。以上是关于如何管理具有递归函数调用的模板类中的数组(以数组的长度作为参数)?的主要内容,如果未能解决你的问题,请参考以下文章