Как я могу специализировать алгоритм для итераторов, которые указывают на сложные значения? - PullRequest
0 голосов
/ 28 января 2020

Я пытаюсь написать алгоритм, который работает на итераторах (аналогично алгоритмам STL), однако мне нужно написать специализацию алгоритма, который будет действовать иначе, когда итераторы указывают на complex значения по сравнению с обычными double значениями.

Вот базовый c пример:

#include <complex>
#include <iostream>
#include <vector>

using namespace std;

template <typename InputIt>
void DoSomething(InputIt first, InputIt last)
{
    cout << "Regular Double" << endl;

    for (; first != last; ++first)
    {
        cout << *first << endl;
    }
}

//// Specialize the template for containers holding complex values
//template <typename InputItToComplex>
//void DoSomething(InputItToComplex first, InputItToComplex last)
//{
//  cout << "Complex Double" << endl;
//
//  for (; first != last; ++first)
//  {
//      cout << *first << endl;
//  }
//}

int main()
{
    vector<double> values = { 1.5, 2.2, 3.1, 4.5, 5.1, 6.9, 7.1, 8.9 };

    // Call the regular template
    DoSomething(values.begin(), values.end());

    vector<complex<double>> cplx_values = { complex<double>{1.4, 2.1}, complex<double>{2.2, 3.5}, complex<double>{7.1, 9.1 } };

    // Need to call the complex specialized version of the template
    DoSomething(cplx_values.begin(), cplx_values.end());
}

Как мне написать специализацию, чтобы она автоматически использовала специализированную версию complex, когда у меня есть контейнер complex ценности? Закомментированный код выше, очевидно, не будет работать, потому что он просто приведет к двум неоднозначным определениям.

Ответы [ 2 ]

2 голосов
/ 28 января 2020

Вы можете использовать SFINAE и std::iterator_traits, чтобы ограничить «специализированный» шаблон. Вам также нужен помощник, чтобы проверить, является ли value_type, возвращаемый чертой итератора, специализацией std::complex. Этот код

template <class T, template <class...> class Template>
struct is_specialization : std::false_type {};

template <template <class...> class Template, class... Args>
struct is_specialization<Template<Args...>, Template> : std::true_type {};

И был написан Квентин здесь

Используя это, вы получите

template <typename InputIt, 
          std::enable_if_t<!is_specialization<typename std::iterator_traits<InputIt>::value_type, std::complex>::value, bool> = true>
void DoSomething(InputIt first, InputIt last)
{
    cout << "Regular Double" << endl;

    for (; first != last; ++first)
    {
        cout << *first << endl;
    }
}

template <typename InputItToComplex, 
          std::enable_if_t<is_specialization<typename std::iterator_traits<InputItToComplex>::value_type, std::complex>::value, bool> = true>
void DoSomething(InputItToComplex first, InputItToComplex last)
{
    cout << "Complex Double" << endl;

    for (; first != last; ++first)
    {
        cout << *first << endl;
    }
}
1 голос
/ 29 января 2020

В качестве альтернативы SFINAE (но все еще требуются черты), в C ++ 17 вы можете использовать if constexpr (даже если обычный if будет работать в текущем фрагменте):

template <typename InputIt>
void DoSomething(InputIt first, InputIt last)
{
    if constexpr (is_specialization<typename std::iterator_traits<InputIt>::value_type,
                                    std::complex>::value) {
        std::cout << "Complex Double" << std::endl;
    } else {
        std::cout << "Regular Double" << std::endl;
    }
    for (; first != last; ++first) {
        std::cout << *first << std::endl;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...