【问题标题】:Creating a function template for double and std::complex that does not require specialization为 double 和 std::complex 创建不需要特化的函数模板
【发布时间】:2021-07-15 08:48:51
【问题描述】:

作为一个学习练习,我试图创建一个就地计算 Hermitian 共轭的函数。当所有条目都是真实的时,它应该表现得像一个简单的转置,因此应该与 double 一起使用。我知道我可以单独专门针对双精度,并且在这个特定示例中是可行的。但是,我认为对于像 ODE 求解器这样的大型问题,专业化会变得乏味。

我尝试了以下

#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
            }
        }
    }
}

是否有不涉及显式专业化的解决方法?如果有意义的话,有什么方法可以“静态地”使用条件分支?

【问题讨论】:

  • 类似if constexpr (is_value_type_complex_v&lt;value_type&gt;)? (if constexpr 是 C++17,没有标准特性,你必须自己编写)。
  • 旁白:template&lt;typename container_type&gt; 就足够了吗?你不会在任何地方使用value_type

标签: c++ templates metaprogramming template-meta-programming complex-numbers


【解决方案1】:

如果你有 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-07
    • 1970-01-01
    相关资源
    最近更新 更多