Учитывая параметр функции типа Container <T>:: Iterator, как мне добиться определенной перегрузки для определенных типов T? - PullRequest
0 голосов
/ 17 мая 2018

В свободное время я вмешивался в обработку сигналов и пишу свою собственную библиотеку 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
    //...
}

1 Ответ

0 голосов
/ 17 мая 2018

Хорошо, просто отбросьте параметры шаблона Container и T и возьмите только тип итератора;это то, что делают все стандартные библиотечные алгоритмы (например, в <algorithm>).Затем используйте std::iterator_traits, чтобы получить T в качестве итератора value_type.

Теперь для своей специализации вы можете использовать одно из:

  • std::enable_if_t
  • теговая отправка
  • constexpr-if - так что у вас будет одна и та же функция с двумя областями действия для двух случаев.

В этом вопросе:

, если constexpr вместо отправки тега

В этом примере вы увидите пример использования второй опции (tagged dispatch) и пример того, какпреобразовать это в constexpr-if в одном из ответов.

...