2016-07-12 10 views
37

Rozważmy następujący:Dlaczego funkcja automatycznego zwracania działa z nie w pełni zdefiniowanymi typami?

template<typename Der> 
struct Base { 
    // NOTE: if I replace the decltype(...) below with auto, code compiles 
    decltype(&Der::operator()) getCallOperator() const { 
     return &Der::operator(); 
    } 
}; 

struct Foo : Base<Foo> { 
    double operator()(int, int) const { 
     return 0.0; 
    } 
}; 

int main() { 
    Foo f; 
    auto callOp = f.getCallOperator(); 
} 

Chcę utworzyć funkcję składową klasy bazowej CRTP z rodzajem powrotu w zależności od podpisania operator() w klasie pochodnej. Jednak decltype(&Der::operator()) nie kompiluje się; Funkcja członkowska operator() w Foo nie jest widoczna. Zakładam, że dzieje się tak, ponieważ szablon klasy podstawowej jest tworzony przed pełną definicją Foo.

Co zaskakujące, jeśli wstawię auto dla typu zwracanego, kompiluje się. Zakładam, że auto spowodowałoby, że kompilator wywnioskuje typ zwracany z treści funkcji i nie powiedzie się - ponieważ ciało używa nie zdefiniowanego w pełni typu: Foo.

Takie zachowanie jest taka sama zarówno dla MSVC 2015.3 i Clang 3.8

Dlaczego kod zacząć pracować z auto? Czy odliczenie typu auto w jakiś sposób "opóźnia" tworzenie instancji? Lub użyć innego kontekstu niż ręcznie napisane wyrażenie typu zwrotu?

+5

Dobre pytanie. Rewizja. –

+0

Prawdopodobny duplikat odliczenia zwrotnego zwrotu CRTP i C++ 1y (http://stackoverflow.com/questions/19892479/crtp-and-c1y-return-type-deduction) – Holt

+0

Jest to ten sam problem, ale pytanie i odpowiedź to z nieco innego kąta. Tutaj mamy "w jaki sposób dedukcja automatyczna jest inna", powiązane pytanie i jego odpowiedź dotyczą raczej "w jaki sposób mogę wykonać ręczną pracę ekspresywną". Choć może nadal kwalifikować się jako duplikat ... –

Odpowiedz

24

Twoje przypuszczenie jest poprawne. Wyliczony typ powrotu nie jest w rzeczywistości wyprowadzany, dopóki nie jest potrzebny podpis funkcji. Oznacza to, że zostanie on wywnioskowany w kontekście wywołania getCallOperator, w którym to punkcie Foo jest w pełni zdefiniowany.

ta jest określona w 7.1.6.4p12: typ

Powrót odliczenie dla szablonu funkcyjnego z zastępczy w jego zadeklarowanego typu występuje, gdy definicja jest tworzony nawet jeśli ciało funkcji zawiera instrukcji return z operand niezależny od typu.

Powiązane problemy