2016-06-08 24 views
5

Sto implementando un modello decoratore su oggetti immutabili con l'idioma puntatore-implementazione. Fondamentalmente la mia configurazione è simile al seguenteÈ possibile rilevare se l'oggetto è temporaneo all'interno della funzione membro?

struct Object : ObjectBase { 
    void doSmth() override { 
     impl->doSmth(); 
    } 
    // this is the function I'd like to implement 
    Object decorateWith(std::unique_ptr<ObjectDecorator>&&); 
private: 
    std::unique_ptr<ObjectBase> impl; 
}; 

struct ObjectDecorator : ObjectBase { 
    void doSmth() override { 
     // do some stuff 
     impl->doSmth(); 
     // do some more stuff 
    } 
private: 
    std::unique_ptr<ObjectBase> impl; 
}; 

Qui, la funzione decorateWith si suppone di avere un comportamento diverso a seconda del fatto che l'oggetto è Callen su un temporaneo o meno. Se viene richiamato su un oggetto non temporaneo, si suppone che restituisca una nuova istanza Object dove devo fare una copia profonda dell'oggetto corrente e memorizzarla nel unique_ptr del decoratore mentre il puntatore impl del nuovo oggetto stesso sta indicando il decoratore. Se, tuttavia, decorareWith viene chiamato su un temporaneo, è sufficiente creare un ObjectDecorator e spostare semplicemente il puntatore impl dell'oggetto corrente nel puntatore impl dell'arredatore e lasciare che l'oggetto punti al nuovo decoratore.

Per impelare ho bisogno di un modo per determinare dall'interno della chiamata di decorWith se l'oggetto è temporaneo o meno e quindi utilizzare tag-dispatch in base al risultato di tale controllo. È possibile?

Miglior Xodion

EDIT: codice chiamante di esempio potrebbe essere la seguente:

  • decorateWith viene chiamato su un non-temporanea

    int main() { 
        Object x{}; 
    
        // this call does not modify x so it can be reused later 
        Object y = x.decorateWith{std::make_unique<ObjectDecorator>()}; 
        y.doSmth(); 
    
        // do some other stuff here 
    
        // here, if I had moved the impl-unique_ptr in the decorateWith 
        // call this would now segfault since I'd call nullptr->doSmth(); 
        x.doSmth(); 
    
    } 
    
  • decorateWith è chiamato a titolo temporaneo

    int main() { 
        Object x = Object{}.decorateWith(std::make_unique<ObjectDecorator>()) 
             .decorateWith(std::make_unique<ObjectDecorator>()) 
             .decorateWith(std::make_unique<ObjectDecorator>()); 
        // in this case it would be unneccessary to make a deep copy of all 
        // previous instances so I'd like to only move the impl poiner every time 
        x.doSmth() 
    } 
    
+1

La spiegazione potrebbe essere meglio sottoposta a backup con codice di chiamata di esempio. – kfsone

+2

Stai chiedendo di determinare se 'Object'' decorWith' è chiamato da è temporaneo, o se l'argomento di 'decorWith' è temporaneo? – md5i

+0

Voglio spostarmi condizionatamente solo quando l'oggetto su cui decorareWith viene chiamato è temporaneo e crea una copia profonda altrimenti, quindi si tratta di verificare se un oggetto è temporaneo. Come dimostrano le risposte di seguito, non è necessario alcun tipo di tratto di tipo poiché è possibile sovraccaricare l'uso di qualificatori di riferimento. – Corristo

risposta

12

È possibile avere qualifiche di riferimento sulle funzioni membro. esempio Copiato da en.cppreference.com

#include <iostream> 
struct S { 
    void f() & { std::cout << "lvalue\n"; } 
    void f() &&{ std::cout << "rvalue\n"; } 
}; 

int main(){ 
    S s; 
    s.f();   // prints "lvalue" 
    std::move(s).f(); // prints "rvalue" 
    S().f();   // prints "rvalue" 
} 

Quindi nel tuo caso, si vorrebbe avere qualcosa di simile

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &; 
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&; 
+0

Sì, certo, ma tuttavia i qualificatori di riferimento sono ciò di cui ho bisogno. – Corristo

4

È possibile utilizzare qualificatori di riferimento sovraccaricare la funzione di membro simile al modo in cui devi usare const sovraccaricare per const e non const oggetti:

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) const& 
{ 
    // implementation if this is not a temporary 
} 

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) && 
{ 
    // implementation if this IS a temporary 
} 
2

Sì. Se si sceglie di implementare i seguenti due metodi:

Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &; 
Object decorateWith(std::unique_ptr<ObjectDecorator>&&) &&; 

il secondo sarà chiamato se *this è un rvalue.