I implemented a C++ equivalent of Python’s chain function a while ago thanks to variadic templates. The function is used to iterate successively through many containers. Here is the old working version of the function using a generator named ChainedObject, whatever it is:
template<typename... Iterables>
auto chain(Iterables&&... iters)
-> ChainObject<Iterables...>
{
return /* ... */;
}
And the corresponding main:
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;
}
That main worked fine. We don’t care what there is in ChainObject for the problem, so let’s see it. I tried to use template templates to ensure that the different collections used had the same value_type and modified the function chain the following way:
template<typename T, template<typename...> class... Iterables>
auto chain(Iterables<T>&&... iters)
-> ChainObject<T, Iterables...>
{
return /* ... */;
}
I thought this would do the trick to ensure the list and vector from my previous main share a same type, but instead, I get the following error from GCC 4.7.1:
In function ‘int main()’:
error: no matching function for call to ‘chain(std::vector&, std::list&)’
note: candidates are:
note:
ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]note: no known conversion for argument 2 from ‘
std::list<int>‘ to ‘std::list<int>&&‘note:
ChainObject<T, Iterables ...> chain(Iterables<T>&& ...) [with T = int; Iterables = {std::vector, std::list}]note: no known conversion for argument 2 from ‘
std::list<int>‘ to ‘std::list<int>&&‘error: unable to deduce ‘auto&’ from ”
It seems that the problem comes from argument passing to the function taking rvalue references. However, I really don’t understand why my first version worked fine, and note the one using template templates.
Your problem is that the
T&&template magic only works for type parameters (it works by deducingTas eg.int&if needed – for lvalue arguments). It can’t work for template template arguments, where the actual type isX<T>&&–Xmust be a class template in this case, not something like “reference-to-class-template”. So in the end you have to pass a rvalue-reference, which you cannot implicitly get from a lvalue (variable).That said, I would suggest you to revert to your earlier code and check that the
value_types are the same (or compatible, etc., whatever gets you going) with SFINAE.Rough code sketch (for strict equality):