I am trying to implement some functional constructs in c++. Wanted to implement a function that flattens list of lists any number of levels down.
template<typename T, typename R>
struct Fold{
typedef R(*func)(T, R);
};
template<typename T>
T head(std::list<T> const& list) {
return list.front();
}
template<typename T>
std::list<T> tail(std::list<T> list) {
list.pop_front();
return list;
}
template<typename T>
std::list<T> cons(T head, std::list<T> tail){
tail.push_front(head);
return tail;
}
template<typename T, typename ACCUM>
ACCUM foldl(typename Fold<T, ACCUM>::func function, ACCUM accum, std::list<T> list) {
if(list.empty())
return accum;
return foldl(function, (*function)(head(list), accum), tail(list));
}
template<typename T, typename ACCUM>
ACCUM foldr(typename Fold<T, ACCUM>::func function, ACCUM accum, std::list<T> list) {
if(list.empty())
return accum;
return (*function)(head(list), foldr(function, accum, tail(list)));
}
template<typename T>
std::list<T> reverse(std::list<T> list){
struct LAMBDA{
static std::list<T> reverse(T t, std::list<T> tList){
return cons(t, tList);
}
};
std::list<T> revTList;
return foldl( static_cast<typename Fold<T, std::list<T>>::func>(&LAMBDA::reverse), revTList, list);
}
template<typename T>
std::list<T> append(std::list<T> list1, std::list<T> list2) {
struct LAMBDA{
static std::list<T> append_lambda(T t, std::list<T> list){
return cons(t, list);;
}
};
return foldl( static_cast<typename Fold<T, std::list<T>>::func>(&LAMBDA::append_lambda), list2, reverse(list1));
}
template<typename T, typename Ty>
struct Flattener{
static std::list<T> flatten(typename std::list<Ty> deepList){
struct LAMBDA{
static Ty flatten_lambda(Ty ty, Ty accum){
return append(ty, accum);
}
};
Ty ty;
Ty flat = foldr( static_cast<typename Fold<Ty, Ty>::func>(&LAMBDA::flatten_lambda), ty, deepList);
return Flattener::flatten(flat);
}
};
template<typename T>
struct Flattener<T, T>{
static std::list<T> flatten(std::list<T> list){
return list;
}
};
The above code compiles fine, but when I attempt to call the function with
std::list<int> emptyList;
std::list<int> list1 = cons(1, cons(2, cons(3, cons(4, emptyList))));
std::list<int> list2 = cons(5, cons(6, cons(7, cons(8, emptyList))));
std::list<std::list<int>> emptyDeepList;
std::list<std::list<int>> deepList = cons(list1, cons(list2, emptyDeepList));
Flattener<int, std::list<int>>::flatten(deepList);
I get this huge error when compiling the code:
error C2664: 'Flattener<T,Ty>::flatten' : cannot convert parameter 1 from 'std::list<T>' to 'std::list<T>'
with
[
T=int,
Ty=std::list<int>
]
and
[
T=int
]
and
[
T=std::list<int>
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
list.h(212) : while compiling class template member function 'std::list<T> Flattener<T,Ty>::flatten(std::list<std::list<T>>)'
with
[
T=int,
Ty=std::list<int>
]
main.cpp(67) : see reference to class template instantiation 'Flattener<T,Ty>' being compiled
with
[
T=int,
Ty=std::list<int>
]
If I remove the call to Flattener::flatten
the code compiles.
What am I doing wrong? (As I am new to c++ and template programming, some explanation would be really helpful too).
Edit:
Tried this. Same Error. I think I am onto something.
template<typename T, typename L>
struct Flattener{
static std::list<T> flatten(L list){
struct LAMBDA{
static std::list<T> flatten_lambda(typename L1 l1, std::list<T> tList){
return append(Flattener<T, L1>::flatten(l1), tList);
}
};
std::list<T> tList;
return foldl(&LAMBDA::flatten_lambda, tList, list);
}
};
template<typename T>
struct Flattener<T, typename std::list<T>>{
static std::list<T> flatten(std::list<T> list){
return list;
}
};
And here's the compiler error for this one:
error C2664: 'Flattener<T,L>::flatten' : cannot convert parameter 1 from 'std::list<T>' to 'std::list<T>'
with
[
T=int,
L=std::list<std::list<int>>
]
and
[
T=std::list<std::list<int>>
]
and
[
T=std::list<int>
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called