定点组合子和显式结果类型

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()::]'

         self(self, t);
Run Code Online (Sandbox Code Playgroud)

(第7条):

prog.cc:20:13:错误:函数'operator()<(lambda at prog.cc:15:24)>'带有推导的返回类型,在定义之前不能使用

        self(self, t);

        ^
Run Code Online (Sandbox Code Playgroud)

prog.cc:24:10:注意:在实例化函数模板特化'main()::(匿名类):: operator()<(lambda at prog.cc:15:24)>'在这里请求

print(print, {1, {{2, {{8}}}, {3, {{5, {{7}}}, {6}}}, {4}}});

     ^
Run Code Online (Sandbox Code Playgroud)

prog.cc:15:24:注意:'operator()<(lambda at prog.cc:15:24)>'在这里声明

const auto print = [&] (const auto & self, const tree & node)

                   ^
Run Code Online (Sandbox Code Playgroud)

生成1个错误.

错误的原因是什么?我认为编译器可以推断出看函数体的结果类型.结果类型不依赖于"模板" self参数类型.

Bar*_*rry 2

[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)的类型(“具有未推导的占位符类型的实体”)来确定表达式的类型,因此我们与第一句话发生了冲突。printoperator()

  • 为什么需要这种类型?天真地,该行中的任何内容都无法更改推导的返回类型,无论它具有什么类型。该标准是否还不够狭窄,如果是的话,您可以引用该部分吗? (2认同)