2016-06-30 12 views
4

Ich habe folgendes Programm:C++ 11: Warum kann result_of Funktortyp als lvalue_reference akzeptieren, aber nicht als lvalue_reference?

#include<type_traits> 
#include<iostream> 
using namespace std; 
template <class F, class R = typename result_of<F()>::type> 
R call(F& f) { return f(); } 

struct S { 
    double operator()(){return 0.0;} 
}; 
int f(){return 1;} 
int main() 
{ 
    S obj; 
    call(obj);//ok 
    call(f);//error! 
    return 0; 
} 

Es scheitert in der Zeile "call (f)" zu kompilieren. Es ist seltsam, dass "Anruf (Obj)" in Ordnung ist.

(1) Ich habe einen ähnlichen Beitrag in einem anderen Thread C++11 result_of deducing my function type failed. Aber es erklärt nicht, warum funktor Objekte in Ordnung sind, während Funktionen nicht sind.

(2) Ich bin mir nicht sicher, ob dies mit "R call (F & f)" zusammenhängt: ein Funktionstyp kann keinen L-Wert deklarieren?

(3) Solange ich weiß, sollte jedes Token mit einem Namen, wie Variable/Funktion, als ein l-Wert betrachtet werden. Und im Falle des Funktionsparameters sollte der Compiler meinen Funktionsnamen "f" zu einem Funktionszeiger "zerlegen", richtig?

(4) Dies ist wie ein Array verfallen und übergeben Sie es an eine Funktion ---- Und ein Funktionszeiger könnte ein l-Wert sein, was ist dann falsch mit "call (F & f)"?

Würdest du mir helfen, weitere Erklärungen zu geben, warum "ist" mein Fall, wo bin ich falsch gelaufen? Danke.

+1

Vielleicht aus dem gleichen Grund, dass Sie nicht sagen können, Vorlage struct F {}; F {}; ' –

Antwort

5

Das Problem mit call(f) ist, dass Sie F als einen Funktionstyp ableiten, so dass es nicht zu einem Funktionszeiger zerfällt. Stattdessen erhalten Sie einen Verweis auf eine Funktion. Dann ist der Ausdruck result_of<F()> ungültig, weil F()int()() ist, d. H. Eine Funktion, die eine Funktion zurückgibt, die in C++ kein gültiger Typ ist (Funktionen können Zeiger auf Funktionen oder Verweise auf Funktionen, aber keine Funktionen zurückgeben).

Es wird funktionieren, wenn Sie result_of<F&()> verwenden, die ohnehin genauer ist, denn das ist, wie Sie das aufrufbare Objekt sind aufgerufen wird. Innerhalb call(F& f) tun Sie f() und in diesem Zusammenhang f ist ein L-Wert, so sollten Sie sich fragen, was das Ergebnis eines lvalue F ohne Argumente aufrufen, sonst könnte man die falsche Antwort. Bedenken Sie:

struct S { 
    double operator()()& {return 0.0;} 
    void operator()()&& { } 
}; 

Jetzt result_of<F()>::type ist void, das ist nicht die Antwort Sie wollen.

Wenn Sie result_of<F&()> verwenden, dann erhalten Sie die richtige Antwort, und es funktioniert auch, wenn F ein Funktionstyp ist, so funktioniert call(f) auch.

(3) Solange ich weiß, sollte jedes Token mit einem Namen, wie Variable/Funktion, als ein l-Wert betrachtet werden. Und im Falle des Funktionsparameters sollte der Compiler meinen Funktionsnamen "f" zu einem Funktionszeiger "zerlegen", richtig?

Nein, siehe oben. Ihre call(F&)-Funktion nimmt ihr Argument als Referenz, so dass es keinen Zerfall gibt.

(4) Das ist wie ein Array abklingenden und es an eine Funktion ---- Und ein Funktionszeiger könnte ein l-Wert, dann das, was mit "Call (F & f)" falsch?

Arrays verfallen nicht, wenn Sie sie als Referenz übergeben.

Wenn Sie möchten, dass das Argument zu verfallen, sollten Sie schreiben call(F f) nicht call(F& f). Aber selbst wenn Sie das tun, müssen Sie immer noch result_of korrekt verwenden, um das Ergebnis f() zu erhalten, wobei f ein Lvalue ist.

Verwandte Themen