Я реализовал C ++ эквивалент функции цепочки Python некоторое время назад благодаря шаблонам с переменным числом аргументов. Функция используется для последовательной итерации во многих контейнерах. Вот старая рабочая версия функции с использованием генератора с именем ChainedObject
, что бы это ни было:
template<typename... Iterables>
auto chain(Iterables&&... iters)
-> ChainObject<Iterables...>
{
return /* ... */;
}
И соответствующие основные:
int main()
{
std::vector<int> vec = { 1, 2, 3, 4, 5 };
std::list<int> li = { 6, 7, 8, 9, 10, 11, 12, 13 };
for (auto& i: chain(vec, li))
{
// You can edit a range of iterables
// as if there was only one of them.
i *= 5;
std::cout << i << std::endl;
}
return 0;
}
Это главное работало нормально. Нам все равно, что есть в ChainObject для этой проблемы, так что давайте посмотрим. Я попытался использовать шаблоны шаблонов, чтобы гарантировать, что различные использованные коллекции имели одинаковые value_type
и изменил функцию chain
следующим образом:
template<typename T, template<typename...> class... Iterables>
auto chain(Iterables<T>&&... iters)
-> ChainObject<T, Iterables...>
{
return /* ... */;
}
Я думал, что это поможет добиться того, чтобы list
а также vector
из моего предыдущего основного ресурса того же типа, но вместо этого я получаю следующую ошибку из GCC 4.7.1:
В функции ‘int main ()’:
ошибка: нет подходящей функции для вызова ‘chain (std :: vector&, std :: list&)»
примечание: кандидаты:
нота:
ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}
]примечание: нет известного преобразования для аргумента 2 из ‘
std::list<int>
кstd::list<int>&&
‘нота:
ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]
примечание: нет известного преобразования для аргумента 2 из ‘
std::list<int>
кstd::list<int>&&
‘ошибка: невозможно вывести ‘auto&’ от »
Кажется, что проблема связана с передачей аргументов в функцию, принимающую rvalue ссылки. Однако я действительно не понимаю, почему моя первая версия работала нормально, и обратите внимание на ту, в которой используются шаблоны шаблонов.
Ваша проблема в том, что T&&
шаблон магии работает только для параметров типа (он работает путем вывода T
как например int&
при необходимости — для аргументов lvalue). Это не может работать для аргументов шаблона шаблона, где фактический тип X<T>&&
— X
в этом случае должен быть шаблоном класса, а не чем-то вроде «reference-to-class-template». Таким образом, в конце вы должны передать rvalue-ссылку, которую вы не можете неявным образом получить из lvalue (переменной).
Тем не менее, я бы посоветовал вам вернуться к предыдущему коду и проверить, что value_type
s одинаковы (или совместимы и т. д., что бы вы ни делали) с SFINAE.
Грубый набросок кода (для строгого равенства):
template <class ... Ts> struct all_types_equal
{
static const bool value = false;
};
template <class T>
struct all_types_equal<T>
{
static const bool value = true;
};
template <class T, class ... Rest>
struct all_types_equal<T, T, Rest...>
{
static const bool value = all_types_equal<T, Rest...>::value;
};
template<typename... Iterables>
auto chain(Iterables&&... iters)
-> typename std::enable_if<all_types_equal<Iterable::value_type...>::value, ChainObject<Iterables...> >::type
Других решений пока нет …