2015-11-24 19 views
21

Desidero dichiarare la funzione std::make_unique come amico della mia classe. Il motivo è che voglio dichiarare il mio costruttore protected e fornire un metodo alternativo per creare l'oggetto usando unique_ptr. Ecco un esempio di codice:Come rendere std :: make_unique un amico della mia classe

#include <memory> 

template <typename T> 
class A 
{ 
public: 
    // Somehow I want to declare make_unique as a friend 
    friend std::unique_ptr<A<T>> std::make_unique<A<T>>(); 


    static std::unique_ptr<A> CreateA(T x) 
    { 
     //return std::unique_ptr<A>(new A(x)); // works 
     return std::make_unique<A>(x);   // doesn't work 
    } 

protected: 
    A(T x) { (void)x; } 
}; 

int main() 
{ 
    std::unique_ptr<A<int>> a = A<int>::CreateA(5); 
    (void)a; 
    return 0; 
} 

Proprio ora ottengo questo errore:

Start 
In file included from prog.cc:1: 
/usr/local/libcxx-head/include/c++/v1/memory:3152:32: error: calling a protected constructor of class 'A<int>' 
return unique_ptr<_Tp>(new _Tp(_VSTD::forward<_Args>(__args)...)); 
         ^
prog.cc:13:21: note: in instantiation of function template specialization 'std::__1::make_unique<A<int>, int &>' requested here 
    return std::make_unique<A>(x);  // doesn't work 
       ^
prog.cc:22:41: note: in instantiation of member function 'A<int>::CreateA' requested here 
std::unique_ptr<A<int>> a = A<int>::CreateA(5); 
            ^
prog.cc:17:5: note: declared protected here 
A(T x) { (void)x; } 
^ 
1 error generated. 
1 
Finish 

Qual è il modo corretto di dichiarare std::make_unique come un amico della mia classe?

+0

prova a compilare con clang - si lamenta: 'main.cpp: 17: 39: errore: gli amici possono essere solo classi o funzioni - amico' std :: unique_ptr > std :: make_unique >(); 'con il la posizione dell'errore è l'istanziazione del modello. – marko

+0

È interessante notare che il compilatore con -std = C++ 14 e questo scompare, e gli errori puntano verso la risposta di @ Praetorian sotto. – marko

+0

@marko L'errore precedente è con clang. Sono su MSVC (vs 2013) ora però. Non funziona neanche lì. – TheCrafter

risposta

16

make_unique inoltra in modo perfetto gli argomenti passati; nel tuo esempio stai passando un lvalue (x) alla funzione, quindi dedurrà il tipo di argomento come int&. La vostra dichiarazione di funzione friend ha bisogno di essere

friend std::unique_ptr<A> std::make_unique<A>(T&); 

Allo stesso modo, se si dovesse move(x) all'interno CreateA, la dichiarazione friend avrebbe bisogno di essere

friend std::unique_ptr<A> std::make_unique<A>(T&&); 

In questo modo ottenere il codice per compile, ma non è in alcun in modo da garantire che verrà compilato su un'altra implementazione perché, per quel che ne sai, make_unique inoltra i suoi argomenti a un'altra funzione di helper interna che effettivamente istanzia la tua classe, nel qual caso l'helper dovrebbe essere uno friend.

+0

In effetti funziona! Ma cosa succede se voglio passare più argomenti al mio costruttore? Se il mio costruttore è ad esempio 'A (const std :: string & str1, const std :: shared_ptr & ptr1)' che è più complesso di un intero. – TheCrafter

+2

@TheCrafter Penso che dovrai fare amicizia con la corrispondente firma 'make_unique', non penso che diventi più generico perché la specializzazione parziale dei modelli di funzione non è consentita. Il mio suggerimento è di dimenticare 'make_unique' e di avere' CreateA' return 'unique_ptr (nuovo A (...))'. A differenza di 'make_shared',' make_unique' non ti offre molti vantaggi. – Praetorian

+0

Ok ho capito. Volevo solo sapere se c'è una soluzione !!Grazie per la risposta :) – TheCrafter