Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用新模板参数递归调用模板化函数 我试图在C++中实现一些功能性构造。想要实现一个函数,可以将列表的列表按任意级别展平 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; } };_C++_Templates_Visual C++_Functional Programming - Fatal编程技术网

使用新模板参数递归调用模板化函数 我试图在C++中实现一些功能性构造。想要实现一个函数,可以将列表的列表按任意级别展平 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; } };

使用新模板参数递归调用模板化函数 我试图在C++中实现一些功能性构造。想要实现一个函数,可以将列表的列表按任意级别展平 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; } };,c++,templates,visual-c++,functional-programming,C++,Templates,Visual C++,Functional Programming,下面是这一个的编译器错误: 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:

下面是这一个的编译器错误:

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
错误C2664:“展平器::展平”:无法将参数1从“std::list”转换为“std::list”
具有
[
T=int,
L=std::列表
]
和
[
T=std::list
]
和
[
T=std::list
]
没有可执行此转换的用户定义的转换运算符,或者无法调用该运算符

错误消息的第一个内容应该是:

参数1从“std::list”到的转换未知 静态成员函数“static”中的“std::list>” std::列表展平器::展平(std::list)[带T=int; Ty=std::list]':

错误编译器?还是糟糕的粘贴

由此得出结论,您希望另一个称为“更改”的扁平化器:

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<T,T>::flatten(flat);
    }
};
模板
结构平坦器{
静态标准::列表展平(typename标准::列表深度列表){
结构LAMBDA{
静态Ty展平λ(Ty,Ty累计){
返回追加(ty,acum);
}
};
蒂;
Ty展平=foldr(静态展平(&LAMBDA::展平LAMBDA),Ty,深度列表);
返回展平器::展平(展平);
}
};

注意额外的

正如@tMJ所指出的,编写
flatter
将消除编译错误,但是
flatter::flatter
方法将只能两次展平两级深度列表(实际上,当您尝试展平m嵌套列表,其中
m>=3
时,会返回错误,因为我们将再次出现类型不匹配)


为了使这项工作适用于具有m个级别的列表
std::list
declytype
节省时间

template<typename T>
list<T> _flattenOneLevel(list<list<T>> listOfTList) {
    auto lambda = [](list<T> tList, list<T> accumList) {
        return reverse(tList, accumList);
    };

    return reverse(foldl(lambda, empty_list<T>(), listOfTList));
}

template<typename T, typename _DeepList>
struct _Flattener {
    static list<T> flatten(_DeepList deepList) {

        auto oneLevelDown = _flattenOneLevel(deepList);
        return _Flattener<T, decltype(oneLevelDown)>::flatten(oneLevelDown);
    }
};

template<typename T>
struct _Flattener<T, list<T>> {
    static list<T> flatten(list<T> list) {
        return list;
    }
};

template<typename T, typename _DeepList>
list<T> flatten(_DeepList deepList) {
    return _Flattener<T, _DeepList>::flatten(deepList);
}
模板
列表_扁平化一级(列表列表){
自动lambda=[](列表tList,列表accumList){
返回反向(tList、accumList);
};
返回反向(foldl(lambda,empty_list(),listOfTList));
}
模板
结构平坦器{
静态列表展平(_deeplistdeeplist){
auto-oneLevelDown=\u FlatteOneLevel(深度列表);
返回_展平器::展平(oneLevelDown);
}
};
模板
结构平坦器{
静态列表展平(列表){
退货清单;
}
};
模板
列表展平(_deeplistdeeplist){
返回_展平器::展平(深度列表);
}

阅读有关递归模板中类型推断的更多信息:

我觉得你的方法相当复杂。因此,让我分享我的解决方案,我希望它适合你。如果你真的想更正代码,而不是解决问题,这不是合适的答案。 我共享的所有代码都已使用visual 2015进行了三级递归测试,但它应该可以在任何具有任何递归级别的编译器上运行

让我们从第一个问题开始。您的解决方案需要提供数据的类型,但该类型已经已知。那么如何自动恢复它呢?我们将使用以下结构:

template <typename T>
struct NestedListType {
  using type = T;
};
接下来,我们需要定义我们的函数。我们需要一个将嵌套类型的每个列表放在一个大列表中的函数。为了避免不必要的副本,我们也将结果列表传递到函数的参数中,因此我们需要第一个函数来实现这一点:

// if you do not want to modify the original list, this is here where you should remove the reference and make a copy
// T could be itself an std::list, no problem with that
template <typename T>
std::list<typename NestedListType<T>::type> flatten(std::list<T> & list) {
  // obtain a std::list with the appropriate type
  std::list<typename NestedListType<T>::type> result;
  flatten(list, result);
  return result;
}
//如果您不想修改原始列表,您应该在此处删除引用并制作副本
//T本身可能是一个std::list,这没问题
模板
标准::列表展平(标准::列表和列表){
//获取具有适当类型的std::list
std::列表结果;
展平(列表、结果);
返回结果;
}
最后,我们需要做实际工作。我们需要两个函数:一个是接收列表并分派每个列表的函数,另一个是接收列表并将其添加到结果中的函数。为此,我们只需使用重载,因为我们不能(也不需要)部分专门化函数:

template <typename T, typename V>
void flatten(std::list<std::list<T> > & list, std::list<V> & result) {
  // if you want to change the order or the resulting list, change here
  // here simply add the first list first and continue until the last
  for (auto & sublist : list)
    flatten(sublist, result);
}

template <typename T, typename V>
void flatten(std::list<T> & list, std::list<V> & result) {
  // add the list to our result using references and splice to avoid unecessary copies or move
  result.splice(result.end(), list);
}
模板
空洞展平(标准::列表和列表,标准::列表和结果){
//如果要更改顺序或结果列表,请在此处进行更改
//这里只需先添加第一个列表,然后继续到最后一个列表
用于(自动和子列表:列表)
展平(子列表、结果);
}
模板
空洞展平(标准::列表和列表,标准::列表和结果){
//使用引用和拼接将列表添加到结果中,以避免不必要的副本或移动
result.splice(result.end(),list);
}
仅此而已!现在,您只需将其与所需的列表和子列表一起使用即可:

std::list<int> l1{ 1, 2, 3 };
std::list<int> l2{ 4, 5, 6 };
std::list<int> l3{ 7, 8, 9 };
std::list<int> l4{ 10, 11, 12 };

std::list<std::list<int> > sl1{ l1, l2 };
std::list<std::list<int> > sl2{ l3, l4 };

std::list<std::list<std::list<int> > > ssl{ sl1, sl2 };

auto result1 = flatten(l1); // gives { 1, 2, 3 }
auto result2 = flatten(sl1); // gives { 1, 2, 3, 4, 5, 6 }
auto result3 = flatten(ssl); // gives { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
...
std::列表l1{1,2,3};
列表l2{4,5,6};
std::列表l3{7,8,9};
std::列表l4{10,11,12};
std::list sl1{l1,l2};
std::列表sl2{l3,l4};
std::list ssl{sl1,sl2};
auto result1=展平(l1);//给出{1,2,3}
auto result2=flant(sl1);//给出{1,2,3,4,5,6}
auto result3=flatten(ssl);//给出{1,2,3,4,5,6,7,8,9,10,11,12}
...
希望有帮助!
如果有什么不清楚的地方,请告诉我,我会尽力解释得更好。

不确定,但是
Fold::func
需要一个
typename
,因为它是依赖的。此外,
return flatter::flatte(flat);
是无限递归的(或者更确切地说,如果类型允许它编译,它将是无限递归的)。它没有选择类的专门化,因为这里的
flatte
指的是它所使用的实例。对于第一个注释,我也这么认为,但是编译器没有显示错误,然后我习惯了不写。切题,它仍然可以在没有提到
typename
的情况下工作。第二个注释,我请看,我如何重做以实现我想要的。您可以编写
flatter::flatten
,其中
A
B
是相关的类型,可能是相同的单一类型?粘贴错误,抱歉,编辑掉了容器的实际名称。但据我所知,更改是y
template<typename T>
list<T> _flattenOneLevel(list<list<T>> listOfTList) {
    auto lambda = [](list<T> tList, list<T> accumList) {
        return reverse(tList, accumList);
    };

    return reverse(foldl(lambda, empty_list<T>(), listOfTList));
}

template<typename T, typename _DeepList>
struct _Flattener {
    static list<T> flatten(_DeepList deepList) {

        auto oneLevelDown = _flattenOneLevel(deepList);
        return _Flattener<T, decltype(oneLevelDown)>::flatten(oneLevelDown);
    }
};

template<typename T>
struct _Flattener<T, list<T>> {
    static list<T> flatten(list<T> list) {
        return list;
    }
};

template<typename T, typename _DeepList>
list<T> flatten(_DeepList deepList) {
    return _Flattener<T, _DeepList>::flatten(deepList);
}
template <typename T>
struct NestedListType {
  using type = T;
};
template <typename T>
struct NestedListType<std::list<T> > {
  using type = typename NestedListType<T>::type;
};
using DataType = typename NestedListType<std::list<std::list<int>>>::type; // DataType will be int
// if you do not want to modify the original list, this is here where you should remove the reference and make a copy
// T could be itself an std::list, no problem with that
template <typename T>
std::list<typename NestedListType<T>::type> flatten(std::list<T> & list) {
  // obtain a std::list with the appropriate type
  std::list<typename NestedListType<T>::type> result;
  flatten(list, result);
  return result;
}
template <typename T, typename V>
void flatten(std::list<std::list<T> > & list, std::list<V> & result) {
  // if you want to change the order or the resulting list, change here
  // here simply add the first list first and continue until the last
  for (auto & sublist : list)
    flatten(sublist, result);
}

template <typename T, typename V>
void flatten(std::list<T> & list, std::list<V> & result) {
  // add the list to our result using references and splice to avoid unecessary copies or move
  result.splice(result.end(), list);
}
std::list<int> l1{ 1, 2, 3 };
std::list<int> l2{ 4, 5, 6 };
std::list<int> l3{ 7, 8, 9 };
std::list<int> l4{ 10, 11, 12 };

std::list<std::list<int> > sl1{ l1, l2 };
std::list<std::list<int> > sl2{ l3, l4 };

std::list<std::list<std::list<int> > > ssl{ sl1, sl2 };

auto result1 = flatten(l1); // gives { 1, 2, 3 }
auto result2 = flatten(sl1); // gives { 1, 2, 3, 4, 5, 6 }
auto result3 = flatten(ssl); // gives { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }
...