复杂浮点类型的 C++20 概念

C++20 concept for complex floating point types

我正在尝试学习 C++20 中的概念,并且我有一个代表数据样本的 class。我想将此 class 限制为仅接受浮点类型或复杂的浮点类型,但我似乎无法弄清楚如何使用概念处理复杂的值。

没有概念这很简单,但它允许太多我不想允许的其他数据类型。

没有概念的例子:

template <typename T>
class Sample
{
    // ...
};

int main()
{
    // This compiles
    Sample<double> s1;
    Sample<complex<double>> s2;

    // This also compiles (but I don't want it to!)
    Sample<int> s3;
    // This compiles as well (again, I don't want it to!)
    Sample<complex<int>> s4;
}

有了概念,我可以很容易地将它限制为只接受浮点值,但它不适用于复杂的值。

template<floating_point T>
class Sample
{
    // ...
};

int main()
{
    // This compiles
    Sample<double> s1;
    Sample<float> s2;

    // This does NOT compile (but I do want it to!)
    Sample<complex<double>> s3;
}

我如何创建一个概念来限制模板同时处理实数和复数浮点值?

一点实验表明您可以这样做:

template <class T>
concept is_floating_point_or_complex = std::is_floating_point_v<T> || std::is_same_v <T, std::complex <double>>;

template<is_floating_point_or_complex T>
class Sample
{
    // ...
};

但是如何避免在 is_floating_point_or_complex 中专门化 std::complex 并不明显(如果您确实想要)。

Live demo

这是一个解决方案,它使用部分特化来检查 T 是否是 std::complex 对浮点类型的特化:

template <typename T>
struct is_complex : std::false_type {};

template <std::floating_point T>
struct is_complex<std::complex<T>> : std::true_type {};

有了这个,就可以写出概念了:

template <typename T>
concept complex = std::floating_point<T> || is_complex<T>::value;

这里是 demo

这里的代码使用具有部分特化的辅助类型特征 class 来确定一个类型是否是具有浮点坐标的复杂类型。

#include <type_traits>
#include <concepts>
#include <complex>

template <typename T>
struct is_complex_floating_point : public std::false_type {};

template <typename T>
struct is_complex_floating_point<std::complex<T>>
    : public std::bool_constant<std::is_floating_point_v<T>>
{};

template <typename T>
concept real_or_complex_floating_point =
    std::floating_point<T> || 
    is_complex_floating_point<std::remove_const_t<T>>::value;

template<real_or_complex_floating_point T>
class Sample
{
    // ...
};

我使用 remove_const_t 因为 std::floating_pointconst float 等满足,这意味着您现有的 Sample(带有约束参数)将允许 Sample<const double>,等等。所以这个概念被定义为接受const std::complex<T>,使Sample<const std::complex<double>>等工作。如果这不应该被认为是有效的,您可以删除 remove_const_t 部分并可能还考虑限制您的模板以禁止 cv-qualified 类型。

[正如@cigien 在 中注意到的那样,使用 std::floating_point 概念编写 is_complex_floating_point 的偏特化更简单。 reader 的练习。 ;)]