2017-09-28 17 views
6

wykonać kilka cyklicznych zadań lokalnie Używam następujące podejście do tworzenia operator paradoksalny w lokalu:operator paradoksalny i wyraźny efekt typu

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

to działa dobrze i nadrukami:

1 
2 
    8 
3 
    5 
    7 
    6 
4 

Ale jeśli usuniemy jawnie określony typ wyniku -> void, otrzymam błąd kompilacji (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); 

(dzyń 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.

Co jest przyczyną tego błędu? Myślę, że kompilator może wydedukować typ wyniku patrząc na treść funkcji. Typ wyniku nie jest zależny od typu parametru "template" self.

Odpowiedz

2

Zasadą [dcl.spec.auto] jest:

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.

Jeśli jawnie określić void jako typ zwracany, nie ma undeduced typ zastępczy, więc jesteśmy w porządku.

Ale jeśli nie, to kiedy wzywamy

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

W wyrażeniu self(self, t), konieczna jest typem print „s operator() (an«podmiot z undeduced rodzaju zastępczego») w celu określenia rodzaj wyrażenia, więc wywołujemy afoul tego pierwszego zdania.

+0

Typ 'print' jest prostą klasą z szablonem' operator() '. Sama klasa mogę przejść tu i tam. – Orient

+0

Czy rozumiem, że 'print.operator()' jest jednostką w wyrażeniu 'self (self, t)'? – Orient

+0

@Orient Tak, chodzi mi o 'operator()' to podmiot, którego typ określamy. – Barry

3

Aby wydedukować typ zwracany, tworzona jest instancja lambda (lepiej, jej operator połączenia) i wymaga ona pełnego zdefiniowania, głównie dlatego, że typ zwracany jest wyprowadzany z każdej nieprzesłanej instrukcji return. Kiedy używasz go z wnętrza ciała, nie jest on jeszcze w pełni zdefiniowany z oczywistych powodów, a zatem typ zwrotu jest wciąż nieznany. Dlatego nie można powiedzieć, jaki jest rodzaj wyrażenia, a program jest źle sformułowany.

+0

W każdym razie, kiedy patrzę na ciało lambda, stwierdzam, że jest wystarczająco dużo informacji, aby wywnioskować typ wyniku. – Orient

+0

@Właściciel Cóż, nie jesteś kompilatorem, nie ma sensu, że czasami nie przestrzegasz standardów pedantycznie. :-) – skypjack

Powiązane problemy