2016-01-04 21 views
5

C'è un modo per verificare se class ha un typedef che funziona anche per privatetypedef?Tratto che controlla se la classe ha typedef (privato o altro) o meno

Seguendo codice funziona in VS2013, ma non riesce a ideone's gcc

template<typename T> 
struct to_void 
{ 
    typedef void type; 
}; 

class Foo 
{ 
    typedef int TD; 
}; 

template <typename T, typename dummy = void> 
struct has_TD : std::false_type {}; 

template <typename T> 
struct has_TD<T, typename to_void<typename T::TD>::type > : std::true_type{}; 

int main() 
{ 
    std::cout << std::boolalpha << has_TD<Foo>::value << std::endl; 
} 

modifica - perché voglio questo

ho sistema di serializzazione personalizzata, che può serializzare tipo arbitrario. Ha diversi sovraccarichi quando deve comportarsi in modo diverso (ad esempio stringa). Per il resto dei tipi, scrive semplicemente il valore nella memoria. Se ho composto il tipo, a volte posso anche solo scrivere in memoria (salva il carico & sulla stessa architettura, compilato con lo stesso compilatore, quindi gli paddings saranno gli stessi, ecc.). Questo metodo è valido ad esempio per i tipi di POD (tratto std::is_pod), ma tutti i tipi di POD è solo un sottoinsieme di tutti i tipi, supportando questa serializzazione.

Quindi ho fondamentalmente la funzione di modello write<T> che basta scrivere sizeof(T) byte (serializzazione raw) ... Ma non voglio che questo venga chiamato per errore, voglio utente, per dire esplicitamente nella loro classe: "questo class/struct può essere serial-serializzato "). Il modo in cui lo faccio è una macro ALLOW_RAW_SERIALIZE che definisce alcuni typedef che possono essere controllati tramite tratto. Se la classe MyClass non contiene typedef, chiamando write(myClassInstance) si verificherà un errore del compilatore.

Le cose che fondamentalmente decidono se la classe può essere serializzata in modo raw sono i suoi membri (senza riflessione, i membri non possono essere enumerati e controllati automaticamente, quindi l'utente deve fornire tali informazioni). classe tipica assomiglia a questo:

class 
    public 
    ctor-dtor 
    methods 
    private 
    methods 
    members 

e voglio gli utenti per consentire scrittura ALLOW_RAW_SERIALIZE il più vicino ai membri più possibile, in modo che quando cambiano alcuni membri v'è una probabilità minore di dimenticato di aggiornare ALLOW_RAW_SERIALIZE (rimuoverla quando. non è più valida è)

Ecco perché voglio verificare un private typedef

Dal momento che è sostituto per la riflessione e prende tutto il tipo e scrivere, io non caduto su di esso come rompere l'incapsulamento o giù di lì ..

+0

perché il downvote? – relaxxx

+0

Questo non sembra possibile. Il comportamento VS sembra un insetto. –

+1

Solo curioso: quale sarebbe il punto di sapere che c'è un typedef che non puoi usare? Se fosse possibile, interromperà l'incapsulamento in quanto le modifiche ai dettagli di implementazione privati ​​influenzano il codice del client nonostante l'API pubblica sia stabile. –

risposta

1

UPDATE:

OK, ho fatto una piccola ricerca.

FYI, il motivo [probabile] che ideone non è stato compilato è che quello che stai facendo ha bisogno di -std=c++11 [o successivo]. Ho avuto errori simili prima di aggiungerlo. Ma, ho dovuto usare clang++ come g++ ancora problemi di compilazione se TD era private.

Ma, non sono sicuro che funzioni come l'unica combinazione che è stata stampata vera se lo TD era pubblico. Tutti gli altri di pubblico/privato e cambiando TD a TF prodotto falso. Forse VS2013 funziona [perché?], Ma altri due compilatori hanno problemi, sia nella compilazione che nei risultati di runtime - YMMV.

La base per ciò che si sta facendo è std::integral_constant [dal C++ 11].Sembra che non ci sia una derivazione standard da questo per quello che stai facendo. Cioè, da http://www.cplusplus.com/reference/type_traits/integral_constant/ l'elenco dei caratteri di tipo [a sinistra] non ha nulla che corrisponda al tuo caso d'uso [AFAICT].

Né lo Boost.TypeTraits ha nulla che corrisponda a [di nuovo, AFAICT].

dal libro di Andrei Alexandrescu: "++ design moderno C: programmazione generica e Design Patterns applicata", sezione 2.10 Tipo Tratti:

solito, si scrivere i propri modelli di tratto e classi come il tuo codice generico bisogno di loro . Alcuni tratti, tuttavia, sono applicabili a qualsiasi tipo. Possono aiutare i programmatori generici ad adattare il codice del modello alle capacità di un tipo.

Quindi, è "okay" eseguire il rollover, se lo si desidera.

Ma anche il TypeTraits di cui parla [da Loki], di nuovo, non ha nulla che corrisponda a quello che stai facendo.

Poiché né lo std né lo Boost hanno qualcosa, la domanda diventa "che cos'è lo standard?" [dalla tua prospettiva]. Potrebbe esserci una libreria di caratteri C++ "fludger" da qualche parte che ha un'implementazione, ma sarebbe considerata "standard"? YMMV

Tuttavia, un paio di domande:

, perché uno fare questo? A cosa serve? Che dire di un typedef protetto in una classe base?

E, questo sembra richiedere la conoscenza della parte privata di una classe e non sarebbe una violazione di "occultamento dei dati" o incapsulamento [senza una dichiarazione friend di qualche tipo]?

Quindi, se questa ultima domanda è vero, la probabile [IMO] risposta è che non v'è alcun modo standard per fare questo, perché non è qualcosa che si dovrebbe stia facendo in una libreria standard.


Nota a margine: Questa è la parte che ha ottenuto downvoted (prima di [veramente] capito la domanda). Credo di essermi assolto sopra. Quindi, ignorare la risposta qui sotto.

Quando si utilizza class la predefinita visibilità è private. Con struct, è public.

Quindi, o lo fanno:

struct Foo 

Oppure:

class Foo 
{ 
    public: 
    typedef int TD; 
}; 

Questo è, naturalmente, a patto che abbiate desideraTD di essere public

+0

Non voglio specificare 'TD' come' pubblico'. Sto chiedendo, se esiste un modo standard per verificare l'esistenza di un typedef 'privato' – relaxxx

+0

Questo non sta rispondendo alla domanda. – juanchopanza

+0

@juanchopanza Capito, mio ​​male. Ma, sto cercando una risposta. –

0

Se tutto ciò che serve è compilare il controllo del tempo, quindi il seguente codice dovrebbe fare:

#include <iostream> 

class Foo 
{ 
    typedef int TD; 
    template<typename T> friend class has_TD; 
}; 

template <typename T> 
struct has_TD 
{ 
    typedef typename T::TD type; 
}; 

template <typename T, typename has_TD<T>::type = 0> 
void write(const T& /*data*/) 
{ 
    std::cout << "serialize" << std::endl; 
} 

int main() 
{ 
    Foo foo; 
    write(foo); 
}