问题
I'm writing an implementation of zip
, but I've ran into a bit of a problem. Here's a minimal test case:
#include <iostream>
#include <deque>
#include <tuple>
#include <string>
#include <limits>
template <template <typename...> class Container, typename... Types>
Container<std::tuple<Types...>> zip(Container<Types> const&... args) {
unsigned len = commonLength(args...);
Container<std::tuple<Types...>> res;
std::tuple<Types...> item;
for (unsigned i=0; i<len; i++) {
item = getTupleFrom(i, args...);
res.push_back(item);
}
return res;
}
template <class ContainerA, class... Containers>
unsigned commonLength(ContainerA first, Containers... rest, unsigned len=std::numeric_limits<unsigned>::max()) {
unsigned firstLen = first.size();
if (len > firstLen) {
len = firstLen;
}
return commonLength(rest..., len);
}
template <class ContainerA>
unsigned commonLength(ContainerA first, unsigned len=std::numeric_limits<unsigned>::max()) {
unsigned firstLen = first.size();
if (len > firstLen) {
len = firstLen;
}
return len;
}
template <template <typename...> class Container, typename TypeA, typename... Types>
std::tuple<TypeA, Types...> getTupleFrom(unsigned index, Container<TypeA> const& first, Container<Types> const&... rest) {
return std::tuple_cat(std::tuple<TypeA>(first[index]), getTupleFrom(index, rest...));
}
template <template <typename...> class Container, typename TypeA>
std::tuple<TypeA> getTupleFrom(unsigned index, Container<TypeA> const& first) {
return std::tuple<TypeA>(first[index]);
}
int main() {
std::deque<int> test1 = {1, 2, 3, 4};
std::deque<std::string> test2 = {"hihi", "jump", "queue"};
std::deque<float> test3 = {0.2, 8.3, 7, 123, 2.3};
for (auto i : zip(test1, test2, test3)) {
std::cout << std::get<0>(i) << std::get<1>(i) << std::get<2>(i) << std::endl;
}
//expected output:
//1hihi0.2
//2jump8.3
//3queue7
return 0;
}
When compiling I get the following error:
error: no matching function for call to ‘commonLength(const Star::List<int>&, const Star::List<std::basic_string<char> >&, const Star::List<float>&)’
note: candidates are:
note: template<class ContainerA, class ... Containers> unsigned int Star::commonLength(ContainerA, Containers ..., unsigned int)
note: template<class ContainerA> unsigned int Star::commonLength(ContainerA, unsigned int)
I'm assuming I'm specifying my template parameters wrong or something like that. I also attempted to restructure and eliminate that function altogether, but then I get the same error against getTupleFrom
.
Can anyone explain to me why I'm stupid? Because I just don't know what I'm doing wrong. :(
回答1:
Well, this works:
#include <iostream>
#include <deque>
#include <tuple>
#include <string>
#include <type_traits>
#include <algorithm>
#include <limits>
template <class ContainerA>
unsigned commonLength(unsigned len, const ContainerA &first) {
unsigned firstLen = first.size();
if (len > firstLen) {
len = firstLen;
}
return len;
}
template <class ContainerA, class... Containers>
unsigned commonLength(unsigned len, const ContainerA &first, const Containers&... rest) {
unsigned firstLen = first.size();
if (len > firstLen) {
len = firstLen;
}
return commonLength(len, rest...);
}
template <template <typename...> class Container, typename TypeA>
std::tuple<TypeA> getTupleFrom(unsigned index, Container<TypeA> const& first) {
return std::tuple<TypeA>(first[index]);
}
template <template <typename...> class Container, typename TypeA, typename... Types>
std::tuple<TypeA, Types...> getTupleFrom(unsigned index, Container<TypeA> const& first, Container<Types> const&... rest) {
return std::tuple_cat(std::tuple<TypeA>(first[index]), getTupleFrom(index, rest...));
}
template <template <typename...> class Container, typename... Types>
Container<std::tuple<Types...>> zip(Container<Types> const&... args) {
unsigned len = commonLength(std::numeric_limits<unsigned>::max(), args...);
Container<std::tuple<Types...>> res;
std::tuple<Types...> item;
for (unsigned i=0; i<len; i++) {
item = getTupleFrom(i, args...);
res.push_back(item);
}
return res;
}
int main() {
std::deque<int> test1 = {1, 2, 3, 4};
std::deque<std::string> test2 = {"hihi", "jump", "queue"};
std::deque<float> test3 = {0.2, 8.3, 7, 123, 2.3};
for (auto i : zip(test1, test2, test3)) {
std::cout << std::get<0>(i) << std::get<1>(i) << std::get<2>(i) << std::endl;
}
//expected output:
//1hihi0.2
//2jump8.3
//3queue7
}
It outputs exactly what you expected. The problems were:
- You weren't using
const&
containers incommonLength
, whilezip
's arguments where const references. - The unsigned parameter in
commonLength
coudln't be deduced, so I moved it to the beginning - You declared/defined functions in the wrong order(A required B, but A was defined before B), so I reordered them.
Apparently clang 3.1 fails to deduce the template arguments in zip
, but g++ 4.6 gets them fine.
回答2:
Picking step by step.
You are missing headers:
#include <limits>
You have undeclared identifiers:
template <template <typename...> class Container, typename TypeA, typename... Types>
std::tuple<TypeA, Types...> getTupleFrom(unsigned index, Container<TypeA> const& first, Container<Types> const&... rest) {
return std::tuple_cat(std::tuple<TypeA>(first[index]), getTupleFrom(index, rest...), end);
}
where is end
declared?
You are inconsistent:
Container<std::tuple<Types...>> zip(Container<Types> const&... args) {
unsigned len = commonLength(args...);
Container<std::tuple<Types...>> res;
Is it Container<std::tuple<Types...>>
or Container<Types>
? Or is this exactly what you mean? Your code is a bit complex for just a quick review.
Then, you have only versions of getTupleFrom
for non-zero counts of Container<TypeA>
,
template <template <typename...> class Container, typename TypeA, typename... Types>
std::tuple<TypeA, Types...> getTupleFrom(unsigned index, Container<TypeA> const& first, Container<Types> const&... rest) {
return std::tuple_cat(std::tuple<TypeA>(first[index]), getTupleFrom(index, rest...), end);
}
template <template <typename...> class Container, typename TypeA>
std::tuple<TypeA> getTupleFrom(unsigned index, Container<TypeA> const& first) {
return std::tuple<TypeA>(first[index]);
}
which is why there is an error of
error: no matching function for call to ‘getTupleFrom(unsigned int&)’
which indicates that you somehow reached a point where your argument list is empty (except for the unsigned integer argument). I guess you need to prevent this.
来源:https://stackoverflow.com/questions/11397484/variadic-template-no-matching-function-call