2017-06-12 6 views
3

Ich lerne C++. Ich möchte den Compiler veranlassen, nullptr als shared_ptr abzuleiten. Bitte lesen Sie den folgenden Code,Wie kann ich Compiler eine Art von Nullptr ableiten lassen?

struct A {}; 

struct B { 
    std::shared_ptr<A> a; 
}; 

struct Tag { 
    std::shared_ptr<B> b; 
}; 

auto GetSharedPtrClassB(Tag* tag) { 
    if (tag) { 
     auto& sharedB = *(tag->b); 
     return sharedB.a; 
    } else { 
     return nullptr; // Error : compiler cannot deduce type of nullptr. 
    } 
} 

In GetSharedPtrClassB, nullptr nicht als std::shared_ptr<A> abgeleitet werden. Die Fehlermeldungen sind folgende,

error: inconsistent deduction for ‘auto’: ‘std::shared_ptr<A>’ and then ‘std::nullptr_t’ 

Wie kann ich lassen Compiler deduce nullptr als std::shared_ptr<A>? Ich kann einen Typ decltype(*(tag->b)) bereitstellen, aber ich kann nicht an den nächsten Schritt denken, um einen Typ std::shared_ptr<A> bereitzustellen.

Vielen Dank.

+1

Es ist besser, das tatsächliche Problem zu zeigen, da jetzt jeder erraten muss, welcher Ansatz am besten passt ([XY Problem] (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)) ... Sehen Sie auch, wie Sie eine gute Frage stellen können: [mcve] (https://stackoverflow.com/help/mcve) –

Antwort

8

einen bedingten Operator Verwenden Sie die Umwandlung von nullptr zu zwingen, "was auch immer":

auto GetSharedPtrClassB(Tag* tag) { 
    return tag ? tag->b->a : nullptr; 
} 

Umwandlung von einem Operanden zum anderen in einem Bedingungsoperator ist gut definiert (siehe [expr.con d]), hier wird die nullptr in ein Objekt vom Typ decltype(tag->b->a) konvertiert.

Auf der anderen Seite sind die Regeln für den Abzug Rückgabetyp, wenn auto ohne Hinterrückgabetyp verwenden, sind sehr streng - die abgeleitete Typ die gleiche für jede return Anweisung sein muss ([dcl.spec.auto/9]):

Wenn eine Funktion mit einem Rückgabetyp deklariert, die einen Platzhalter Typ enthält mehrere return-Anweisungen hat, der Rückgabetyp für jede return-Anweisung abgeleitet wird. Wenn der abgeleitete Typ nicht in jedem Abzug gleich ist, ist das Programm schlecht gebildet.


Wenn Ihre Funktion nicht auf einen bedingten Operator reduziert werden kann, können Sie einen nachgestellten Rückgabetyp verwenden:

auto GetSharedPtrClassB(Tag* tag) -> decltype(tag->b->a) { 
    if (tag) { 
     auto& sharedB = *(tag->b); 
     return sharedB.a; 
    } else { 
     return {}; 
    } 
} 
+0

Dies ist der funktionalste Vorschlag, ich fühle – sehe

+1

@sehe Ich denke, ich habe etwas noch besser gefunden, siehe bearbeiten;) – Holt

+0

@Holt: Vielen Dank für die Beantwortung. Aber es gibt mir einen Fehler "ETV Initialisierungsliste". – mora

4

Sie können stattdessen einen standardmäßig erstellten shared_ptr zurückgeben.

auto GetSharedPtrClassB(Tag* tag) { 
    if (tag) { 
     auto& sharedB = *(tag->b); 
     return sharedB.a; 
    } else { 
     return std::shared_ptr<A>{}; 
    } 
} 
+0

: Danke für das Kommentieren. In meinem tatsächlichen Code kann Klasse A wegen Meta-Programmierung C sein. Also ich möchte den Typ shared_ptr <'X'> ableiten lassen. – mora

+0

@mora - Sorry für AFK. Die Antwort von Holt ist genau das, was Sie tun sollten, um den Abzug hinzuzufügen. Ich schlage vor, dass Sie diese Antwort akzeptieren. – StoryTeller

+0

es war meine weniger Erklärung. Ihre Antwort ist eine Lösung für mich. Danke, dass du es noch einmal beantwortet hast. – mora

1

Sie static_cast wie diese verwenden:

auto GetSharedPtrClassB(Tag* tag) { 
    if (tag) { 
     auto& sharedB = *(tag->b); 
     return sharedB.a; 
    } else { 
     return static_cast<std::shared_ptr<A> >(nullptr); 
    } 
} 
+0

: Danke für das Kommentieren. In meinem tatsächlichen Code kann Klasse A wegen Meta-Programmierung C sein. Also ich möchte den Typ shared_ptr <'X'> ableiten lassen. – mora

+0

Ok verpasst, dass ... –

2

Ich gehe davon aus, dass der Code tatsächlich in einem allgemeinen Kontext verwendet wird. Wenn Ihr Code keine Vorlagen verwendet, verwenden Sie nicht decltype, geben Sie Typen direkt an.

Um den Rückgabetyp abzuleiten, müssen alle Rückgabeanweisungen zu einem Ausdruck des gleichen Typs auswerten. In Ihrem Code haben Sie zwei Rückgabeanweisungen mit zwei verschiedenen Typen. Eine mit std::shared_ptr<A> und eine mit std::nullptr_t.

Es gibt zwei Lösung: Verwenden Sie die gleichen Typen in beiden Return-Anweisungen, oder definieren Sie explizit einen Rückgabetyp.

Hier ist, wie die gleiche Art zurück:

auto GetSharedPtrClassB(Tag* tag) { 
    if (tag) { 
     auto& sharedB = *(tag->b); 
     return sharedB.a; 
    } 

    // empty constructor same as initializing with `nullptr` 
    return decltype(tag->b->a){}; 
} 

oder explizit einen Rückgabetyp definieren:

auto GetSharedPtrClassB(Tag* tag) -> decltype(tag->b->a) { 
    if (tag) { 
     auto& sharedB = *(tag->b); 
     return sharedB.a; 
    } 

    // empty constructor same as initializing with `nullptr` 
    return {}; 
} 

By the way, in Sie Code auto& sharedB = *(tag->b); return sharedB.a; zu return tag->b->a; reduziert werden konnte

+0

danke, dass du mir zwei Möglichkeiten erklärst, decltype zu verwenden. – mora

Verwandte Themen