2015-07-20 4 views
7

Ho visto uno CRTP solution, che ha estratto l'interfaccia nella classe base e ha condiviso solo uno degli argomenti del pacchetto per classe base. Quindi la classe più derivata ha ereditato tutte le classi di base amichevoli e ha implementato l'interfaccia.C'è un modo per specificare tutte le classi in un pacchetto di parametri variadici per essere amico del modello per utilizzare operator =?

Non riesco a utilizzare questo approccio, poiché è necessario proteggere l'operatore di assegnazione, che non è ereditato.

Inoltre, poiché l'operatore di assegnazione ha una firma definita con esattamente un parametro, non è possibile utilizzare uno key pattern.

Questo è quello che mi piacerebbe avere:

template <typename... F> 
struct A { 
protected: 
    A& operator=(const SomeClass &other) { 
     //... 
    } 
private: 
    //I would like to do the following, but it does not work 
    friend F...; 
} 

Esiste un modo per fare quello che sto bisogno?

+0

IDGI. Cosa deve essere un amico di cosa? E perché? Cosa è 'A'? Cos'è 'SomeClass'? Cosa sono 'F ...' in questo esempio? –

+0

@LightnessRacesinOrbit 'A' è auto esplicativo, è una classe con operatore protetto =' attorno al quale sta la mia domanda. 'SomeClass' è solo per completezza sulla firma' operator = '. Si riferisce ad alcune altre classi, non correlate né importanti per questo esempio. 'F ...' è l'argomento del pacchetto di parametri passato al template, che voglio rendere amico a 'A'. Può contenere altre classi non correlate e sconosciuto a 'A', ma dovrebbero avere accesso a' operator = ', come ad altri metodi, che ho estratto usando il pattern di interfaccia di cui ho parlato nella mia domanda. – LoPiTaL

+0

o.O hummmmmmmmm –

risposta

4

Bene, puoi sempre giocare sporco. In primo luogo, definire una macro ripetizione:

#define REPEAT_2(M, N) M(N) M(N+1) 
#define REPEAT_4(M, N) REPEAT_2 (M, N) REPEAT_2(M, N+2) 
#define REPEAT_8(M, N) REPEAT_4 (M, N) REPEAT_4(M, N+4) 
#define REPEAT_16(M, N) REPEAT_8 (M, N) REPEAT_8(M, N+8) 
#define REPEAT_32(M, N) REPEAT_16 (M, N) REPEAT_16(M, N+16) 
#define REPEAT_64(M, N) REPEAT_32 (M, N) REPEAT_32(M, N+32) 
#define REPEAT_128(M, N) REPEAT_64 (M, N) REPEAT_64(M, N+64) 

Poi posizionare 128 dichiarazioni di amicizia in un modello di classe variadic di vostra scelta:

template <typename... T> 
class A 
{ 
    #define FRIEND(N) friend std::tuple_element_t< 
         std::min((std::size_t)N+1, sizeof...(T)), std::tuple<void, T...>>; 
    REPEAT_128(FRIEND, 0) 

    static constexpr int i = 3; 
}; 

struct X; struct Y; struct Z; 
using ASpec = A<X, Y, Z>; 
struct X {int i = ASpec::i;}; 
struct Y {int i = ASpec::i;}; 
struct Z {int i = ASpec::i;}; 

template class A<>; // Small test for empty pack 

Demo. Ringraziamento a @dyp.

Se si ha accesso a Boost.Preprocessor, l'intera operazione può essere scritta in modo molto più conciso utilizzando BOOST_PP_REPEAT.

+0

Funziona come un fascino! L'unico problema è che è scritto per C++ 14. Poiché è più o meno facile tornare a C++ 11, dovresti specificare le modifiche necessarie in orer per usarlo: sostituire tuple_element_t con tuple_element :: type; e std :: min con una propria versione di constexpr, poiché la funzione standard, in C++ 11, non è constexpr. A parte questo, funziona perfettamente, grazie. – LoPiTaL

Problemi correlati