Dove dovrei inserire un typedef quando usato nelle firme dei metodi in C ++?

4

Sto usando una classe opzionale abbastanza simile a quella di boost. Per ragioni semantiche, ho cambiato un attributo dello stesso tipo (strutturato) in alcune definizioni di classe (e quindi anche nelle firme dei metodi) da obbligatorio a facoltativo. Quindi, in ogni file di intestazione di classe correlato, ho incluso l'intestazione con la definizione di Facoltativo e anche un typedef per facilitare la digitazione (vedere CHANGE commenti); i passaggi sono letti in questo modo:

#include <MyAttrType.h>
#include <Optional.h>                          // CHANGE
typedef Optional<MyAttrType> OptionalAttrType  // CHANGE

class MyClassX
{
// ...

Oggi eseguo Cppcheck 1.68 sul progetto e ho ricevuto questo avviso di stile:

The typedef 'OptionalAttrType' hides a typedef with the same name.

Come faccio a sbarazzarmi di questi avvertimenti di stile senza fare qualcosa di male?

Nota:

  • MyAttrType è attualmente indipendente da Optional (perché definito nelle prime fasi della cronologia del progetto, mentre Opzionale era l'ultima volta)
  • Penso di introdurre una nuova intestazione solo per questo scopo. Ma forse ci sono opzioni migliori?
  • Immagino che potrebbe essere generalmente un'indicazione di un cattivo design, di avere molte classi con lo stesso attributo opzionale, ma non sono sicuro nel mio caso particolare. Il codice sta attualmente cambiando per raggiungere obiettivi con priorità più elevata.
  • naturalmente, MyAttrType , OptionalAttrType e MyClassX non sono i nomi effettivi
posta Wolf 05.01.2015 - 13:14
fonte

3 risposte

2

In genere utilizzo uno dei due modi.

  1. Il primo modo è di typedef nella dichiarazione del luogo di prima.
  2. Il secondo modo è di typedef a ogni luogo d'uso, e renderlo visibile solo a quel luogo d'uso (mettendolo nella classe o nel metodo che lo usa) .

(1) Metti il typedef vicino al tipo che si sta tagliando.

/* MyAttrType.h */

#include <Optional.h>

// README : See Optional<MyAttrType> at the end of this header

struct MyAttrType
{
    // ....
};

// (put the typedef here)
typedef Optional<MyAttrType> OptionalMyAttrType;

/* ---------------------------- */
/* Every other C++ source files */
#include "MyAttrType.h"

// .... Any code can use OptionalMyAttrType there.

(2) Rendi visibile il typedef solo per ogni classe che lo utilizza.

/* MyAttrType.h */

namespace my_pod_types
{
    struct MyAttrType { /* ... */ };
}

// (nothing else outside.)

/* ---------------------------- */
/* Every other C++ source files */

#include "MyAttrType.h"
#include "Optional.h"

class MyClassX
{
private:
    typedef Optional<my_pod_types::MyAttrType> OptionalMyAttrType;
public:
    // ...
private:
    OptionalMyAttrType m_optAttr;
};

Nella maggior parte dei casi, il modello pertinente per me è std::unique_ptr e std::shared_ptr . Inoltre, deciderò solo che una classe userà un modo o l'altro, e poi digiterà quel wrapper puntatore intelligente come "MyClassOnePtr". Draconian, ma l'autore principale di una biblioteca dovrebbe sapere qual è il meglio per la biblioteca la maggior parte del tempo.

Se non è ovvio quale dei due puntatori intelligenti dovrebbe essere preferito, allora non inserirò il typedef nella prima intestazione (quindi, non userò l'opzione n. 1 a meno che la scelta sia ovvia.)

Il più delle volte capirai che l'opzione # 2 non protegge sempre l'utilizzo di Optional<T> dall'utente finale. In altre parole, la logica dell'applicazione potrebbe richiedere agli utenti di MyClassX di occuparsi di Optional<T> durante l'interazione con esso. Quando ciò accade, non puoi più nasconderlo. Non è un dettaglio di implementazione; fa parte della superficie visibile.

Infine, dovresti essere consapevole della limitazione del C ++ per inoltrare dichiarazioni. Vale a dire, ci sono dei momenti in cui C ++ ha bisogno di sapere in anticipo:

  • Dimensione del tipo da incapsulare;
  • Esistenza di un costruttore e un distruttore predefiniti;
  • E così via.

Vedi questa domanda su Stackoverflow (circa unique::ptr ) per esempi di tali limitazioni.

Un'altra cosa non correlata che vorrei condividere, dopo aver letto ixrec risposta.

Ho iniziato a seguire una politica "nulla nello spazio dei nomi predefinito" dopo aver scoperto che non è possibile ottenere Doxygen (una documentazione C ++ ampiamente utilizzata nel generatore HTML) per generare una documentazione ben organizzata a meno che non si classifichi le classi utilizzando gli spazi dei nomi. Sembra che non importi il nome di quei namespace; Fintanto che Doxygen li vede come distinti e gli utenti umani non si lamentano, qualsiasi approccio di namespace andrà bene.

    
risposta data 06.04.2015 - 01:29
fonte
0

Se OptionalAttrType fa parte dell'API pubblica definita da tali intestazioni, allora utilizzerei un altro nome per il typedef.

Se OptionalAttrType è un dettaglio di implementazione che non dovresti sapere, allora quelle intestazioni dovrebbero averlo inserito in uno spazio dei nomi per evitare collisioni come questa. Dal momento che non l'hanno fatto, devi lavorare su questo in qualche modo.

Poiché stai facendo questa domanda, presumo che ti aspetti di incontrare più di queste collisioni in futuro, quindi hai bisogno di una soluzione a lungo termine. A meno che tu non possa modificare tutte le intestazioni e i file di origine dai quali dipendere per utilizzare spazi dei nomi o nomi di classi più coerenti, l'unica soluzione generale che posso pensare è scegliere un prefisso o suffisso che difficilmente scontrerà con qualcosa (ad esempio, OptionalAttrType_TD) e iniziare a usare per tutti i tuoi typedef.

Un'alternativa meno generale ma forse più pratica è semplicemente nascondere questo avviso. Il Capitolo 6 di il manuale Cppcheck descrive tutti i modi in cui è possibile eliminare un avvertimento specifico da quello strumento.

    
risposta data 05.01.2015 - 21:28
fonte
0

Ci sono tre errori:

  1. Le tue intestazioni dichiarano un nome in uno spazio dei nomi non privato della tua libreria che non hanno alcuna dichiarazione commerciale.
  2. Sembra che tu non ti assicuri che esiste un'unica definizione in tutta la tua libreria.
  3. Stai tentando di chiudere l'avviso anziché correggere il bug.

Quello che dovresti fare è uno di:

  1. Inseriscilo nella tua interfaccia.
  2. O nascondilo nel tuo spazio dei nomi delle tue librerie (probabilmente in uno spazio dei nomi annidato internal o simile).
  3. O rimuovilo completamente e scrivendo i nomi completi.

Se scegli l'opzione 1 o 2, assicurati che sia definita solo in un unico punto.

    
risposta data 06.04.2015 - 02:33
fonte

Leggi altre domande sui tag