给定一个类型为 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?

本文关键字:类型 实现 重载 参数 函数 lt Container 一个 Iterator gt      更新时间:2023-10-16

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

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


这应该给你一个想法,

//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
//...
}

好吧,只需删除容器和 T 模板参数,只采用迭代器类型; 这就是所有标准库算法(例如在<algorithm>中)所做的。然后使用std::iterator_traits获取T作为迭代器的value_type

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

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

在这个问题中:

如果 constexpr 而不是标签调度

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