如何获取 std::complex<T> 的基础类型并在 class 中使用它

How to get the type underlying std::complex<T> and use it in a class

我正在编写一个数据处理器,希望能够执行实到实、实到复杂的计算。我现在的设置:

// class to hold various data types
template <typename T>
class DataArray
{
public:
    DataArray(){};
    T *ptr;
};

// Processing configuration 
template <typename T>
class Config
{
public:
    Config(){};
    T var;
};

// The data processor itself, takes input, output array and the processing configuration
template <typename Tin, typename Tout>
class Process
{
public:
    DataArray<Tin> *in;
    DataArray<Tout> *out;
    Config<Tout> *config;

    Process(){};
    Process(DataArray<Tin> *in_, DataArray<Tout> *out_, Config<Tout> *config_)
    {
        in = in_;
        out = out_;
        config = config_;
    }
};

目前我可以进行实对实的处理如下:

int main()
{
    DataArray<int16_t> input;
    DataArray<float> output;
    Config<float> config;
    // real 2 real processing
    Process<int16_t, float> P1(&input, &output, &config); // works fine 
    return 0;
}

我面临的问题是,当我想做实数到复数的处理时,我仍然需要我的Configstd::complex<T>的底层类型中。我如何更改 Process class(或任何其他 class),以便我可以创建一个 class Process<int16_t, std::complex<float>>,它知道它需要一个 Config<float>?

int main()
{
    DataArray<int16_t> input;
    DataArray<std::complex<float>> output_complex;
    Config<float> config;

    // real 2 complex processing
    Process<int16_t, std::complex<float>> P2(&input, &output, &config); // Obviously does not work

    return 0;
}

跟进问题 感谢 Remy 的回答,我现在可以在 class Process 中获取 std::complex 的类型。如果我有一个带有模板函数的命名空间,我将如何获得该 function/namespace 中的基础类型?以下工作,但感觉有点笨拙。这意味着我必须在每个内核中重复 using T = typename helper::value_type_of<Tout>::type; 行,对吗?

// namespace with computation kernels
namespace kernels
{
    // define ConfigType in the kernel namespace? 
    template <typename T>
    using ConfigType = Config<typename helper::value_type_of<T>::type>;

    template <typename Tin, typename Tout, bool IQ>
    void bfpw(ConfigType<Tout> *BFC, Tin *RF, Tout *BF)
    {
        // get type of Tout: std::complex<float> or float
        using T = typename helper::value_type_of<Tout>::type;
        T variable = BFC->var;
    }
}

template <typename Tin, typename Tout>
Process<Tin, Tout>::Process(DataArray<Tin> *in_, DataArray<Tout> *out_, ConfigType *config_)
{
    in = in_;
    out = out_;
    config = config_;

    kernels::bfpw<Tin, Tout, true>(config, in->ptr, out->ptr); // call the kernel
}

一种方法是定义一个辅助模板,Process 可以使用它来检测 Tout 是否是 std::complex,如果是,那么它可以使用 Toutvalue_type成员,否则可以用Tout as-is.

例如:

namespace helper {

    template<typename T>
    struct value_type_of {
        using type = T;
    };

    template<typename T>
    struct value_type_of<std::complex<T>> {
        using type = typename std::complex<T>::value_type;
        // or simply: using type = T;
    };
}

template <typename Tin, typename Tout>
class Process
{
public:
    using ConfigType = Config<typename helper::value_type_of<Tout>::type>;

    ...
    ConfigType *config;

    Process(){};
    Process(..., ConfigType *config_)
    {
        ...
        config = config_;
    }
};

Online Demo

这样,Process<..., float>Process<..., std::complex<float>> 都会接受 Config<float>