C++ 中重载乘法运算符的递归 class 模板实例化期间出错
Error during recursive class template instantiation for overloaded multiplication operator in C++
我正在尝试为一个非常特殊的框实现模板 class,称为 H Box。
它包含一个数字向量,其大小始终为 2 的幂。当涉及到结构时,本质上就是它 - 它仅包含一个数组,并重载了 []
运算符以访问其元素。问题是 - 它有一个非常奇特的乘法规则:两个 H Boxes 的乘积归结为将向量分成左半部分和右半部分,创建更小的盒子,将它们交叉相乘,然后最后总结结果(下面代码中的详细信息)。所以问题是乘法运算符被重载为递归函数,它生成越来越小的框。
我的 class 的非模板版本的代码已经可用。但是,在我移动到模板后,我无法正确...
template <typename T, const unsigned int size>
HBox<T, size> operator*(
const HBox<T, size> &H1,
const HBox<T, size> &H2
) {
// recursion base:
if (size == 1) {
T temparr[] = { H1[0] * H2[0] };
HBox<T, 1> H_(temparr);
return H_;
}
// shared objects:
const unsigned int halfsize = size / 2;
T* temparr = new T[size];
// construct helper objects:
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H1[i];
HBox<T, halfsize> H1a(temparr);
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H1[i+halfsize];
HBox<T, halfsize> H1b(temparr);
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H2[i];
HBox<T, halfsize> H2a(temparr);
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H2[i+halfsize];
HBox<T, halfsize> H2b(temparr);
// multiply recursively:
HBox<T, halfsize> H1a2a = H1a * H2a;
HBox<T, halfsize> H2b1b = H2b * H1b;
HBox<T, halfsize> H2b1a = H2b * H1a;
HBox<T, halfsize> H1b2a = H1b * H2a;
// construct the final object
HBox<T, halfsize> Ha = H1a2a + H2b1b;
HBox<T, halfsize> Hb = H2b1a + H1b2a;
for (unsigned int i=0; i < halfsize; i++) temparr[i] = Ha[i];
for (unsigned int i=0; i < halfsize; i++) temparr[i+halfsize] = Hb[i];
HBox<T, size> H(temparr);
delete[] temparr;
return H;
}
我编译了一个简单的测试程序,其中包含两个四元素 float
框 (A * B
) 的乘积:
Run g++ -O0 -Wall --std=c++14 -o test test.cpp
我收到以下错误:
In file included from test.cpp:17:
HBox/HBox.hpp: In instantiation of ‘HBox<T, size> operator*(const HBox<T, size>&, const HBox<T, size>&) [with T = float; unsigned int size = 4]’:
test.cpp:266:44: required from here
HBox/HBox.hpp:276:16: error: could not convert ‘H_’ from ‘HBox<[...],1>’ to ‘HBox<[...],4>’
276 | return H_;
| ^~
| |
| HBox<[...],1>
Error: Process completed with exit code 1.
出了什么问题?在我看来,这里应该一切都很好...
使用模板递归时,您不能将基本情况作为简单 if
提供。这样做的原因是即使某些代码无法访问,整个函数也需要能够编译。一个简单的if (false)
是不够的。
要解决此问题,您可以使用 C++17 的 if constexpr
or partial template specialization:
// using if constexpr
template <typename T, const unsigned int size>
HBox<T, size> operator*(
const HBox<T, size> &H1,
const HBox<T, size> &H2
) {
if constexpr (size == 1) {
// handle base case here
} else {
// handle recursive case here
}
}
或
// using partial template specialization
template <typename T, const unsigned int size>
HBox<T, size> operator*(
const HBox<T, size> &H1,
const HBox<T, size> &H2
) {
// handle recursive case here
}
template <typename T>
HBox<T, 1> operator*<T, 1>( // partial specialization for size == 1
const HBox<T, 1> &H1,
const HBox<T, 1> &H2
) {
// handle base case here
}
即使您的程序在 n != 1 时永远不会进入 if 语句,您的编译器也会尝试编译这样的分支。因此,您可以从必须 return HBox<T, 4>
的函数中 return HBox<T, 1>
。
首先尝试将 constexpr
添加到 if
if constexpr (size == 1)...
如果没有帮助,请尝试使用此代码
HBox<T, size> operator*(const HBox<T, size> &H1, const HBox<T, size> &H2);
template <typename T>
HBox<T, 1> operator*(const HBox<T, 1> &H1, const HBox<T, 1> &H2) {
T temparr[] = {H1[0] * H2[0]};
HBox<T, 1> H_(temparr);
return H_;
}
template <typename T, const unsigned int size>
HBox<T, size> operator*(const HBox<T, size> &H1, const HBox<T, size> &H2) {
// shared objects:
const unsigned int halfsize = size / 2;
T *temparr = new T[size];
// construct helper objects:
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H1[i];
HBox<T, halfsize> H1a(temparr);
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H1[i + halfsize];
HBox<T, halfsize> H1b(temparr);
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H2[i];
HBox<T, halfsize> H2a(temparr);
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H2[i + halfsize];
HBox<T, halfsize> H2b(temparr);
// multiply recursively:
HBox<T, halfsize> H1a2a = H1a * H2a;
HBox<T, halfsize> H2b1b = H2b * H1b;
HBox<T, halfsize> H2b1a = H2b * H1a;
HBox<T, halfsize> H1b2a = H1b * H2a;
// construct the final object
HBox<T, halfsize> Ha = H1a2a + H2b1b;
HBox<T, halfsize> Hb = H2b1a + H1b2a;
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = Ha[i];
for (unsigned int i = 0; i < halfsize; i++) temparr[i + halfsize] = Hb[i];
HBox<T, size> H(temparr);
delete[] temparr;
return H;
}```
我正在尝试为一个非常特殊的框实现模板 class,称为 H Box。
它包含一个数字向量,其大小始终为 2 的幂。当涉及到结构时,本质上就是它 - 它仅包含一个数组,并重载了 []
运算符以访问其元素。问题是 - 它有一个非常奇特的乘法规则:两个 H Boxes 的乘积归结为将向量分成左半部分和右半部分,创建更小的盒子,将它们交叉相乘,然后最后总结结果(下面代码中的详细信息)。所以问题是乘法运算符被重载为递归函数,它生成越来越小的框。
我的 class 的非模板版本的代码已经可用。但是,在我移动到模板后,我无法正确...
template <typename T, const unsigned int size>
HBox<T, size> operator*(
const HBox<T, size> &H1,
const HBox<T, size> &H2
) {
// recursion base:
if (size == 1) {
T temparr[] = { H1[0] * H2[0] };
HBox<T, 1> H_(temparr);
return H_;
}
// shared objects:
const unsigned int halfsize = size / 2;
T* temparr = new T[size];
// construct helper objects:
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H1[i];
HBox<T, halfsize> H1a(temparr);
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H1[i+halfsize];
HBox<T, halfsize> H1b(temparr);
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H2[i];
HBox<T, halfsize> H2a(temparr);
for (unsigned int i=0; i < halfsize; i++) temparr[i] = H2[i+halfsize];
HBox<T, halfsize> H2b(temparr);
// multiply recursively:
HBox<T, halfsize> H1a2a = H1a * H2a;
HBox<T, halfsize> H2b1b = H2b * H1b;
HBox<T, halfsize> H2b1a = H2b * H1a;
HBox<T, halfsize> H1b2a = H1b * H2a;
// construct the final object
HBox<T, halfsize> Ha = H1a2a + H2b1b;
HBox<T, halfsize> Hb = H2b1a + H1b2a;
for (unsigned int i=0; i < halfsize; i++) temparr[i] = Ha[i];
for (unsigned int i=0; i < halfsize; i++) temparr[i+halfsize] = Hb[i];
HBox<T, size> H(temparr);
delete[] temparr;
return H;
}
我编译了一个简单的测试程序,其中包含两个四元素 float
框 (A * B
) 的乘积:
Run g++ -O0 -Wall --std=c++14 -o test test.cpp
我收到以下错误:
In file included from test.cpp:17:
HBox/HBox.hpp: In instantiation of ‘HBox<T, size> operator*(const HBox<T, size>&, const HBox<T, size>&) [with T = float; unsigned int size = 4]’:
test.cpp:266:44: required from here
HBox/HBox.hpp:276:16: error: could not convert ‘H_’ from ‘HBox<[...],1>’ to ‘HBox<[...],4>’
276 | return H_;
| ^~
| |
| HBox<[...],1>
Error: Process completed with exit code 1.
出了什么问题?在我看来,这里应该一切都很好...
使用模板递归时,您不能将基本情况作为简单 if
提供。这样做的原因是即使某些代码无法访问,整个函数也需要能够编译。一个简单的if (false)
是不够的。
要解决此问题,您可以使用 C++17 的 if constexpr
or partial template specialization:
// using if constexpr
template <typename T, const unsigned int size>
HBox<T, size> operator*(
const HBox<T, size> &H1,
const HBox<T, size> &H2
) {
if constexpr (size == 1) {
// handle base case here
} else {
// handle recursive case here
}
}
或
// using partial template specialization
template <typename T, const unsigned int size>
HBox<T, size> operator*(
const HBox<T, size> &H1,
const HBox<T, size> &H2
) {
// handle recursive case here
}
template <typename T>
HBox<T, 1> operator*<T, 1>( // partial specialization for size == 1
const HBox<T, 1> &H1,
const HBox<T, 1> &H2
) {
// handle base case here
}
即使您的程序在 n != 1 时永远不会进入 if 语句,您的编译器也会尝试编译这样的分支。因此,您可以从必须 return HBox<T, 4>
的函数中 return HBox<T, 1>
。
首先尝试将 constexpr
添加到 if
if constexpr (size == 1)...
如果没有帮助,请尝试使用此代码
HBox<T, size> operator*(const HBox<T, size> &H1, const HBox<T, size> &H2);
template <typename T>
HBox<T, 1> operator*(const HBox<T, 1> &H1, const HBox<T, 1> &H2) {
T temparr[] = {H1[0] * H2[0]};
HBox<T, 1> H_(temparr);
return H_;
}
template <typename T, const unsigned int size>
HBox<T, size> operator*(const HBox<T, size> &H1, const HBox<T, size> &H2) {
// shared objects:
const unsigned int halfsize = size / 2;
T *temparr = new T[size];
// construct helper objects:
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H1[i];
HBox<T, halfsize> H1a(temparr);
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H1[i + halfsize];
HBox<T, halfsize> H1b(temparr);
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H2[i];
HBox<T, halfsize> H2a(temparr);
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = H2[i + halfsize];
HBox<T, halfsize> H2b(temparr);
// multiply recursively:
HBox<T, halfsize> H1a2a = H1a * H2a;
HBox<T, halfsize> H2b1b = H2b * H1b;
HBox<T, halfsize> H2b1a = H2b * H1a;
HBox<T, halfsize> H1b2a = H1b * H2a;
// construct the final object
HBox<T, halfsize> Ha = H1a2a + H2b1b;
HBox<T, halfsize> Hb = H2b1a + H1b2a;
for (unsigned int i = 0; i < halfsize; i++) temparr[i] = Ha[i];
for (unsigned int i = 0; i < halfsize; i++) temparr[i + halfsize] = Hb[i];
HBox<T, size> H(temparr);
delete[] temparr;
return H;
}```