给定类型为 Container<T>::Iterator 的函数参数,我如何实现特定类型 T 的特定重载?

Given a function parameter of type Container<T>::Iterator, how do I achieve a specific overload for certain kinds of T?

我一直在空闲时间进行信号处理,并且正在编写自己的 DSP 库作为学习练习。我写了一个函数来计算向量的离散傅立叶变换。该函数有两个重载:一个用于 const std::vector<float> &,另一个用于 std::vector<std::complex<float>>.

我想让它更通用。该函数应该接受一对通用随机访问迭代器,而不是向量。然后,编译器应该从迭代器中推断出它是复值数据还是实值数据以及 select 正确的重载。


这应该会给你一个想法,

//compute the discrete fourier transform in-place for a complex valued input
template<template<typename T> class Container, typename T, class RandomAccessIt>
void fft(
        typename Container<std::complex<T>>::RandomAccessIt first,
        typename Container<std::complex<T>>::RandomAccessIt last
    )
{
    ...
}

//calculate the discrete fourier transform for a real valued input
template<template<typename T> class Container1,
         template<std::complex<T>> class Container2,
         typename T,
         class RandomAccessIt1,
         class RandomAccessIt2>
void fft(
        typename Container1<T>::RandomAccessIt1 first,
        typename Container1<T>::RandomAccessIt1 last,
        typename Container2<std::complex<T>>::RandomAccessIt2 out_first
    )
{
    ...
    fft(...); //call the complex version
    ...        
}

但是如您所见,我真的不知道我在用模板做什么。我怎样才能让它发挥作用?如果不可能,为什么?


编辑:

我最喜欢 if constexpr 方法,因为它非常优雅地解决了问题

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

template<typename T>
struct is_complex_t<std::complex<T>> : public std::true_type {};

template<typename RandomAccessIt>
void fft(RandomAccessIt first, RandomAccessIt last)
{
    using Number_t = typename std::iterator_traits<RandomAccessIt>::value_type;
    if constexpr(!is_complex_t<Number_t>::value)
    {
        //math trickery to transform the real input data to complex-valued data
        ...
    }
    ... //the FFT itself
    if constexpr(!is_complex_t<Number_t>::value)
    {
        //math trickery to properly format the frequency domain data
        ...
    }
}  

也就是说,我已经意识到,由于两个重载具有不同数量的参数,我什至不需要任何巧妙的元编程:

//compute the discrete fourier transform in-place for a complex valued input
template<typename RandomAccessIt>
void fft(RandomAccessIt first, RandomAccessIt last)
{
    //...
}

//calculate the discrete fourier transform for a real valued input
template<typename RandomAccessIt1, typename RandomAccessIt2>
void fft(
        RandomAccessIt1 first, RandomAccessIt1 last,
        RandomAccessIt2 out_first
    )
{
    //...
    //fft(...); //call the complex version
    //...
}

好吧,去掉 Container 和 T 模板参数,只取迭代器类型;这是所有标准库算法(例如 <algorithm>)所做的。然后用std::iterator_traits得到T作为迭代器的value_type.

现在,对于您的专业化,您可以使用以下之一:

  • std::enable_if_t
  • 标记派遣
  • constexpr-if - 因此对于这两种情况,您将拥有具有两个作用域的相同函数。

本题中:

您将在问题中看到如何使用第二个选项(标记为 dispatch)的示例,以及在其中一个答案中如何将其转换为 constexpr-if 的示例。