要在本地执行一些递归任务,我使用以下方法来创建固定点组合器:
#include <utility>
#include <list>
#include <memory>
#include <iostream>
int main()
{
struct tree
{
int payload;
std::list< tree > children = {}; // std::list of incomplete type is allowed
};
std::size_t indent = 0;
// indication of result type here is essential
const auto print = [&] (const auto & self, const tree & node) -> void
{
std::cout << std::string(indent, ' ') << node.payload << '\n';
++indent;
for (const tree & t : node.children) {
self(self, t);
}
--indent;
};
print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}});
}
工作正常并打印:
1
2
8
3
5
7
6
4
但是如果我删除显式指定的结果类型-> void
,那么我得到编译错误(GCC 8):
prog.cc:实例化&#39; main():: [with auto:1 = main()::]&#39;:
prog.cc:24:64:从这里要求
prog.cc:20:17:错误:使用&#39; main():: [与auto:1 = main()::]&#39;在扣除&#39; auto&#39;
之前self(self, t);
(第7条):
prog.cc:20:13:错误:函数&#39;运算符()&lt;(lambda at prog.cc:15:24)>&#39;具有推导的返回类型在定义之前不能使用
self(self, t); ^
prog.cc:24:10:注意:在实例化函数模板特化&#39; main()::(anonymous class):: operator()&lt;(lambda at prog.cc:15:24) &GT;&#39;请求
print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}}); ^
prog.cc:15:24:注意:&#39; operator()&lt;(lambda at prog.cc:15:24)>'在这里宣布
const auto print = [&] (const auto & self, const tree & node) ^
生成了1个错误。
错误的原因是什么?我认为编译器可以推断出看函数体的结果类型。结果类型不依赖于&#34;模板&#34; self
参数类型。
答案 0 :(得分:3)
为了推导返回类型,lambda(更好,它的调用运算符)被实例化,并且需要完全定义,主要是因为返回类型是从任何非丢弃的return语句推导出来的。当你在体内使用它时,由于显而易见的原因它尚未完全定义,因此返回类型仍然是未知的。因此,不可能说出表达的类型是什么,程序是不正确的。
答案 1 :(得分:2)
[dcl.spec.auto]中的规则是:
如果需要具有未减弱占位符类型的实体类型来确定表达式的类型,则程序格式错误。但是,一旦在函数中看到了一个非丢弃的return语句,那么从该语句推导出的返回类型可以在函数的其余部分中使用,包括在其他return语句中。
如果您明确指定print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}});
作为返回类型,则没有未受影响的占位符类型,因此我们很好。
但如果我们不这样做,那么当我们调用
时self(self, t)
在表达式print
中,需要operator()
{{1}}的类型(#34;具有未减少占位符类型的实体&#34;)才能确定表达式的类型,所以我们与第一句话发生冲突。