简体   繁体   中英

Manipulating variadic template argument list

I'd like to manipulate some data with certain types in a template argument list. In my case, I would like to check if some of the elements are some kind of an Iterable, and if there are any, then I want to use std::advance on them.

This is what I had in mind: (well it obviously will not compile but gives you the right idea what I want to achieve here)

#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)...);
    }
}

I think the problem's (maybe?) that, that the argument list gets expanded at compile time and then it will see, that I want to use std::advance on something, that may not even be an Iterable type.

In the code above begin and end are iterators of a data sequence and the partialSize variable tells, that a thread should process only a part of the sequence.

So the goal is, if any other Iterable types are passed through the argument list, say: std::vector<>::iterator or std::list<>::iterator or even a double* , then I would like to std::advance them.

Are there any solutions for this problem? Can I achieve something like this?

I've implemented a function that advances all iterators passed to it. It simply ignores arguments of any other type.

The code requires C++17, but can be ported to earlier versions of standard.

#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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM