2017-09-28 21 views
6

Để thực hiện một số nhiệm vụ đệ quy tại địa phương tôi sử dụng phương pháp sau đây để tạo ra combinator điểm cố định tại chỗ:Fixed điểm combinator và rõ ràng kết quả loại

#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}}}); 
} 

Nó hoạt động tốt và in:

1 
2 
    8 
3 
    5 
    7 
    6 
4 

Nhưng nếu tôi xóa loại kết quả được chỉ định rõ ràng -> void, thì tôi nhận được lỗi biên dịch (GCC 8):

prog.cc: In instantiation of 'main():: [with auto:1 = main()::]':

prog.cc:24:64: required from here

prog.cc:20:17: error: use of 'main():: [with auto:1 = main()::]' before deduction of 'auto'

  self(self, t); 

(clang 7):

prog.cc:20:13: error: function 'operator()<(lambda at prog.cc:15:24)>' with deduced return type cannot be used before it is defined

 self(self, t); 

     ^

prog.cc:24:10: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<(lambda at prog.cc:15:24)>' requested here

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

    ^

prog.cc:15:24: note: 'operator()<(lambda at prog.cc:15:24)>' declared here

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

       ^

1 error generated.

Nguyên nhân gây ra lỗi là gì? Tôi nghĩ rằng trình biên dịch có thể suy ra loại kết quả nhìn vào cơ thể chức năng. Loại kết quả không phụ thuộc vào loại tham số "mẫu" self.

Trả lời

2

Các quy tắc trong [dcl.spec.auto] là:

If the type of an entity with an undeduced placeholder type is needed to determine the type of an expression, the program is ill-formed. Once a non-discarded return statement has been seen in a function, however, the return type deduced from that statement can be used in the rest of the function, including in other return statements.

Nếu bạn chỉ định một cách rõ ràng void như kiểu trả về, không có loại placeholder undeduced, vì vậy chúng tôi đang sử dụng tốt.

Nhưng nếu chúng ta không, sau đó khi chúng tôi gọi

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

Trong biểu self(self, t), loại print 's operator() (một 'thực thể với một loại placeholder undeduced') là cần thiết để xác định loại biểu thức, vì vậy chúng tôi chạy afoul của câu đầu tiên đó.

+0

Loại 'in' là một lớp đơn giản với mẫu' toán tử() '. Lớp tôi có thể vượt qua đây và ở đó. – Orient

+0

Tôi có nên hiểu 'print.operator()' là thực thể trong biểu thức 'self (self, t)'? – Orient

+0

@Orient Vâng, tôi có nghĩa là toán tử '()' là thực thể có kiểu chúng ta đang xác định. – Barry

3

Để suy ra kiểu trả về, lambda (tốt hơn, toán tử gọi của nó) được khởi tạo và nó đòi hỏi phải được xác định đầy đủ, chủ yếu là vì kiểu trả về được trích từ bất kỳ câu lệnh trả về không bị loại bỏ nào. Khi bạn sử dụng nó từ bên trong cơ thể, nó chưa được xác định đầy đủ vì những lý do rõ ràng và do đó kiểu trả về vẫn chưa được biết. Do đó, không thể nói loại biểu thức là gì và chương trình bị hỏng.

+0

Dù sao thì, khi tôi nhìn vào cơ thể của lambda, tôi kết luận rằng có đủ thông tin để suy ra loại kết quả. – Orient

+0

@Orient Vâng, bạn không phải là một trình biên dịch, nó có ý nghĩa rằng bạn không làm theo các tiêu chuẩn pedantically đôi khi. :-) – skypjack

Các vấn đề liên quan