操纵可变参数模板参数列表
Manipulating variadic template argument list
我想在模板参数列表中处理某些具有特定类型的数据。
在我的例子中,我想检查一些元素是否是某种 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
他们。
这个问题有什么解决办法吗?我可以实现这样的目标吗?
我实现了一个函数,可以推进传递给它的所有迭代器。它只是忽略任何其他类型的参数。
代码需要 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;
}
我想在模板参数列表中处理某些具有特定类型的数据。
在我的例子中,我想检查一些元素是否是某种 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
他们。
这个问题有什么解决办法吗?我可以实现这样的目标吗?
我实现了一个函数,可以推进传递给它的所有迭代器。它只是忽略任何其他类型的参数。
代码需要 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;
}