Управление списком аргументов вариационного шаблона - PullRequest
0 голосов
/ 14 апреля 2019

Я хотел бы манипулировать некоторыми данными с определенными типами в списке аргументов шаблона.В моем случае я хотел бы проверить, являются ли некоторые элементы каким-то образом Iterable, и если они есть, то я хочу использовать на них std::advance.

Это то, что я имел впомните: (ну, очевидно, он не скомпилируется, но дает вам правильное представление о том, чего я хочу достичь здесь)

#include <typeinfo>
#include <thread>

template<class _Func, class Iterator, class... _Args>
void
start(_Func pFunc, const Iterator begin, const Iterator end, _Args&&... args)
{
    Iterator pt = begin;
    Iterator ptNext = begin;
    for (unsigned int i = 0; i < this->nThreads(); i++)
    {
        std::advance(ptNext, partialSize);
        this->getThreads(i) = std::thread(pFunc, pt, ptNext, std::forward<_Args>(args)...);
        pt = ptNext;
        [](...){}((typeid(args) == typeid(Iterator) ? std::advance(args, partialSize) : false)...);
    }
}

Я думаю, что проблема (может быть?) в том, что список аргументов расширяется во время компиляциии тогда он увидит, что я хочу использовать std::advance для чего-то, что может даже не иметь типа Iterable.

В приведенном выше коде begin и end являются итераторами последовательности данных ипеременная partialSize сообщает, что поток должен обрабатывать только часть последовательности.

Таким образом, цель состоит в том, чтобы, если любые другие типы Iterable передавались через список аргументов, скажем: std::vector<>::iterator или std::list<>::iterator или даже double*, тогда я бы хотел std::advance их.

Есть ли какие-нибудь решения для этой проблемы?Могу ли я достичь чего-то подобного?

1 Ответ

1 голос
/ 14 апреля 2019

Я реализовал функцию, которая продвигает все итераторы, переданные ей. Он просто игнорирует аргументы любого другого типа.

Код требует C ++ 17, но может быть перенесен на более ранние версии стандарта.

#include <iterator>
#include <type_traits>

template <class T, class = void>
struct is_iterator : std::false_type {};

template <class T>
struct is_iterator<T, std::void_t<typename std::iterator_traits<T>::iterator_category>> : std::true_type {};

template <class Distance, class T>
void advance_if_iterable_impl(Distance n, T& t)
{
    if constexpr (is_iterator<T>::value)
        std::advance(t, n);
}

template <class Distance, class... Args>
void advance_if_iterable(Distance n, Args&... args)
{
    (advance_if_iterable_impl(n, args), ...);
}

#include <iostream>

int main()
{
    int i = 42;
    const char* str = "Hello World!\n";

    advance_if_iterable(2, i, str);

    // `int` isn't an iterator, it stays the same
    std::cout << i << '\n';
    // `const char*` is a random iterator, so it was advanced by two
    std::cout << str;

    return 0;
}
...