如何避免在提供T = std :: complex <Q>时嵌入std :: complex?

6

对于一个多项式方程求解器来说,将其模板化以适应任何类型会非常好:

template <class number, int degree>
class PolynomialEquation
{
public:

private:
    array<number, degree+1> myEquation;
    array<complex<number>, degree> equationResult;
};

这使得例如在 ℝ 中使用 double 作为输入,并且结果在 ℂ 中是std::complex<double>,(我们知道从二次及以上的程度时,解通常会落入 ℂ, 比如:x^2+1)。

但是,方程的输入也可以是一个 std::complex。在这种情况下,myEquation 的类型应该是复数类型,但是 equationResult 不应该是 std::complex<complex<T>>,而只是一个普通类型为 T 的复数。

问题:

如何使当给方程提供 std::complex 时,equationResult 的类型成为 std::complex 的子类型?

是否有类似于 std::is_floating_point 的 std::is_complex_number 相关函数?

4个回答

7
你可以创建一个特征,类似于以下内容:
template <typename T>
struct to_complex {
    using type = std::complex<T>;
};

template <typename T>
struct to_complex<std::complex<T>> {
    using type = std::complex<T>;
};

然后

template <class number, int degree>
class PolynomialEquation
{
public:

private:
    array<number, degree+1> myEquation;
    array<typename to_complex<number>::type, degree> equationResult;
};

1
可能我会称其为poly_root_type_traits或类似的名称 - to_complex对于这个东西背后的基本原理有点不清楚。 - Matteo Italia

2

我认为并没有检查类型是否为复数的特性,但是创建一个相对简单的特性应该不难(也可以采用Jarod的另一种实现方式to_complex):

#include <type_traits>
#include <complex>
#include <iostream>

template <class T>
struct is_complex_number: std::false_type { };

template <class T>
struct is_complex_number<std::complex<T>>: std::true_type { };

template <class T>
struct to_complex: std::conditional<is_complex_number<T>::value, T, std::complex<T>> { };

int main() {
   std::cout << is_complex_number<float>::value << std::endl; // output: 0
   std::cout << is_complex_number<std::complex<float>>::value << std::endl; // output: 1
   typename to_complex<float>::type c; // decltype(c) == complex<float>
   typename to_complex<std::complex<float>>::type d; // decltype(d) == complex<float>
}

我想不到任何一种在一行代码中使用std::same的方法,你呢?在type_traits中是否有检查T是否为模板模板且是否为U<V>形式的内容? - Benoît
@Benoît 如果 V 是类型模板参数,那么可以创建一个带有两个重载的 constexpr 函数:template <class> constexpr bool is_template_template() { return false; } template <template <class> class> constexpr bool is_template_template() { return true; }。不幸的是,我不知道 STL 的方法... - W.F.

2
这里有一个C++14的一行代码替代@W.F.的方法。
using Complex = typename std::conditional<std::is_arithmetic<T>::value, std::complex<T>, T>::type;

假设它不是算术类型,那么它应该是复杂的。如果你想彻底一些,你需要确保T是算术(甚至是浮点)或者复杂的。你需要将这个与@W.F.的答案结合起来。

2

我有一个多项式类,其中可能需要实系数和复数x(以及实数、实数和复数、复数和复数)。我创建了一个is_complex:

/**
 * Introspection class to detect if a type is std::complex.
 */
template<typename _Tp>
  struct is_complex : public std::false_type
  { };

/**
 * Introspection class to detect if a type is std::complex.
 */
template<>
  template<typename _Tp>
    struct is_complex<std::complex<_Tp>> : public std::true_type
    { };

/**
 * Introspection type to detect if a type is std::complex.
 */
template<typename _Tp>
  using is_complex_t = typename is_complex<_Tp>::type;

/**
 * Introspection variable template to detect if a type is std::complex.
 */
template<typename _Tp>
  constexpr bool is_complex_v = is_complex<_Tp>::value;

此外,我使用工具来提取标量类型,无论输入是标量还是复数,以便可以使用数字极限设施,例如:
template<typename Tp>
  struct num_traits
  {
    using __value_type = Tp;
  };

template<>
  template<typename Tp>
    struct num_traits<std::complex<Tp>>
    {
      using __value_type = typename std::complex<Tp>::value_type;
    };

template<typename Tp>
  using num_traits_t = typename num_traits<Tp>::__value_type;

我可以这样使用:

  using Val = num_traits_t<Ret>;
  constexpr auto eps = std::numeric_limits<Val>::epsilon();

接下来,需要为实数和复数输入构建收敛测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接