Вывод типов и передача аргументов с помощью шаблонов с переменными шаблонами

Я реализовал 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 ссылки. Однако я действительно не понимаю, почему моя первая версия работала нормально, и обратите внимание на ту, в которой используются шаблоны шаблонов.

2

Решение

Ваша проблема в том, что T&& шаблон магии работает только для параметров типа (он работает путем вывода T как например int& при необходимости — для аргументов lvalue). Это не может работать для аргументов шаблона шаблона, где фактический тип X<T>&&X в этом случае должен быть шаблоном класса, а не чем-то вроде «reference-to-class-template». Таким образом, в конце вы должны передать rvalue-ссылку, которую вы не можете неявным образом получить из lvalue (переменной).

Тем не менее, я бы посоветовал вам вернуться к предыдущему коду и проверить, что value_types одинаковы (или совместимы и т. д., что бы вы ни делали) с 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
5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]