Ori*_*ent 6 c++ lambda language-lawyer c++14 c++17
要在本地执行一些递归任务,我使用以下方法来创建固定点组合器:
#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}}});
}
Run Code Online (Sandbox Code Playgroud)
它工作正常并打印:
1
2
8
3
5
7
6
4
Run Code Online (Sandbox Code Playgroud)
但是如果我删除显式指定的结果类型-> void
,那么我得到编译错误(GCC 8):
prog.cc:在'main():: [with auto:1 = main()::]'的实例化中:
prog.cc:24:64:从这里需要
prog.cc:20:17:错误:在扣除'auto'之前使用'main():: [with auto:1 = main()::]'
Run Code Online (Sandbox Code Playgroud)self(self, t);
(第7条):
prog.cc:20:13:错误:函数'operator()<(lambda at prog.cc:15:24)>'带有推导的返回类型,在定义之前不能使用
Run Code Online (Sandbox Code Playgroud)self(self, t); ^
prog.cc:24:10:注意:在实例化函数模板特化'main()::(匿名类):: operator()<(lambda at prog.cc:15:24)>'在这里请求
Run Code Online (Sandbox Code Playgroud)print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}}); ^
prog.cc:15:24:注意:'operator()<(lambda at prog.cc:15:24)>'在这里声明
Run Code Online (Sandbox Code Playgroud)const auto print = [&] (const auto & self, const tree & node) ^
生成1个错误.
错误的原因是什么?我认为编译器可以推断出看函数体的结果类型.结果类型不依赖于"模板" self
参数类型.
[dcl.spec.auto]中的规则是:
如果需要具有未推导的占位符类型的实体的类型来确定表达式的类型,则该程序是格式错误的。然而,一旦在函数中看到未丢弃的 return 语句,从该语句推导出的返回类型就可以在函数的其余部分中使用,包括在其他 return 语句中。
如果您显式指定void
为返回类型,则不存在未推导的占位符类型,所以我们没问题。
但如果我们不这样做,那么当我们调用
print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}});
Run Code Online (Sandbox Code Playgroud)
在表达式 中,需要'sself(self, t)
的类型(“具有未推导的占位符类型的实体”)来确定表达式的类型,因此我们与第一句话发生了冲突。print
operator()