为double和std::complex创建一个不需要专门化的函数模板



作为一个学习练习,我试图创建一个函数来计算埃尔米特共轭。当所有条目都是实的时,它应该表现得像一个简单的转置,因此应该使用double。我知道我可以单独为double进行专门化,在这个特定的例子中是可行的。但是,我想,对于像ODE Solvers这样的大问题,专门化会变得乏味。

我尝试了以下

#include <complex>
const size_t ZERO = 0ul;
template <class value_type,
class container_type = value_type*>
auto
hermitianConjugate(container_type buffer, size_t width)
{
for (size_t row = ZERO; row < width; row++)
{
for (size_t col = ZERO; col < width; col++)
{
auto temp = std::conj(buffer[col * width + row]);
if (std::imag(temp) == 0)
{
// works for both double and std::complex
buffer[row * width + col] = buffer[col * width + row];
} else 
{
// for std::complex
buffer[row * width + col] = temp;
// raises error when value_type is double
}
}
}
}

有没有一种不涉及显式专业化的变通方法?有没有任何方法可以使用条件分支";"静态";,如果这有道理的话?

如果您有c++17,则可以使用if-constexpr。这本质上创建了不同的专业化,而不需要编写单独的函数。

#include <complex>
#include <type_traits>
const size_t ZERO = 0ul;
template <class value_type,
class container_type = value_type*>
auto
hermitianConjugate(container_type buffer, size_t width)
{
for (size_t row = ZERO; row < width; row++)
{
for (size_t col = ZERO; col < width; col++)
{
if constexpr (std::is_same_v<value_type, std::complex<double>>) {
// only for complex
buffer[row * width + col] = std::conj(buffer[col * width + row]);
}
else
{
// for double
buffer[row * width + col] = buffer[col * width + row];
}
}
}
}

如果您没有c++17,您可以编写一个重载函数来执行不同的任务,具体取决于类型:

#include <complex>
const size_t ZERO = 0ul;
constexpr double myconj(double x) noexcept { return x; }
std::complex<double> myconj(std::complex<double> x) { return std::conj(x); }
template <class value_type,
class container_type = value_type*>
auto
hermitianConjugate(container_type buffer, size_t width)
{
for (size_t row = ZERO; row < width; row++)
{
for (size_t col = ZERO; col < width; col++)
{
buffer[row * width + col] = myconj(buffer[col * width + row]);
}
}
}

请注意,std::conj已经有一个用于double的专用重载,但在这种情况下,它也返回一个std::complex

最新更新