2010-12-11 36 views
8

Ho ridefinito alcune funzioni matematiche (in modo che siano più veloci, meno precisi o utilizzare i modelli). Metto queste funzioni in un namespace e funzionano bene.C++: nascondendo alcune funzioni

Capita spesso, però, che mi dimentico di chiamare funzioni dal mio spazio dei nomi (ad esempio: ho dimenticato di scrivere mymath::cos o using mymath::cos; quando voglio chiamare cos), ed è abbastanza difficile per scoprire dove ho dimenticato (fino ora l'ho scoperto solo con il profiling).

Dato che

  • ho solo includono standard di math.h o cmath intestazioni all'interno della mia intestazione di matematica, e che
  • ho bisogno di includere le intestazioni matematiche standard (perché alcune delle mie funzioni sono solo wrapper per lo standard uno, e voglio loro di essere in linea o che stanno su modelli),

c'è un modo portatile per nascondere funzione matematica standard in modo che venga segnalato un errore di compilazione, se vengono utilizzate funzioni matematiche globali (ovvero: senza uno spazio dei nomi)?

Una soluzione potrebbe essere mettere un using namespace mymath; nella parte inferiore del mio file di intestazione matematica, ma questa soluzione non sembra così grande: rompe l'intero scopo dei namespace; Preferirei dover dire esplicitamente se usare una funzione da mymath o da std in modo che io sia costretto a scegliere tra un fester o una funzione più accurata senza il rischio di dimenticarlo.


EDIT:

Molte risposte dire che se uso cos dal namespace globale (senza utilizzare né stdmymath), e comprendono cmath (e non math.h), la compilazione dovrebbe fallire.

non so cosa dice la norma su di esso, ma:

#include <cmath> 
int main() { 
    cos(M_PI); 
    return 0; 
} 

compila bene con GNU GCC (g++) 4.5.1 (e versioni precedenti).

+0

Hai ragione riguardo all'EDIT: "Non è specificato se questi nomi siano stati dichiarati per la prima volta all'interno dell'ambito dello spazio dei nomi globale e siano quindi iniettati nello std dei nomi mediante esplicite use-dichiarazioni". – ybungalobill

risposta

4

mettere questo in un file di intestazione, e #include ovunque:

namespace DontUseMe { 
double cos (double) ; 
// ...etc. 
} 
using namespace DontUseMe ; 
+0

Uh, sembra carino! Usando Boost.StaticAssert mi darà errori di compilazione ogni volta che uso una funzione matematica globale nello spazio dei nomi ... – peoro

+3

Beh, qualcuno l'ha votato. Mi chiedo perché! – TonyK

+0

Quando si fa questo e in alcune unità di compilazione 'cmath' è incluso, il compilatore ti dirà che' double cos (double) 'è ambiguo. Da qui il namespace * wrestling *;) –

3

Se si include solo cmath e non math.h, tutte le funzioni da tale intestazione devono trovarsi nello spazio nomi :: std ::. Non usare mai using namespace std; e starai bene. (cmath è solo math.h con tutte le cose in uno spazio dei nomi)

+3

No, non con 'cmath' da GNU GCC 4.5.1.Voglio dire, sì, fornisce funzioni matematiche nel namespace 'std', ma ** ** fornisce anche funzioni matematiche nello spazio dei nomi globale (es .:' :: cos', senza alcun namespace), che è quello che voglio evitare. – peoro

1

Che ne dite di questa idea: dopo compreso < math.h>, utilizzare definire come segue:

#define sin blahblahblah (just to generate an error) 
#define cos blahblahblah (just to generate an error) 

Quello che succede è che ogni peccato sarà sostituito da blahblahblah, che causerà un errore. Ma ciò che accadrà è che mymath :: sin sarà sostituito da mymath :: blahblahblah (perché #define funziona letteralmente), quindi genererà anche un errore. In questo caso, se vuoi semplificare il compito per te, definisci temporaneamente la funzione blahblahblah in mymath per evitare di mostrare l'errore per mymath :: sin, quindi compila e correggi tutti quegli errori.

Tuttavia, consiglierei di creare "Trova nei file" e di esaminare tutte le funzioni, e sono sicuro che non parlerà più di un'ora per un progetto su larga scala.

Spero che questo aiuti.

saluti,
RAFID

+0

Questa è una possibile soluzione. Le funzioni matematiche standard della libreria standard sono spesso macro. –

+0

Hum, sperava di trovare un modo per farlo al momento della compilazione, senza avere due passaggi per la compilazione (uno per verificare la validità delle funzioni e l'altro per compilare effettivamente) ... Comunque sì, funzionerebbe. – peoro

+1

Non funzionerà, dovresti definirli come macro di stile della funzione e dovresti controllarli e "undef" perché possono essere macro (così come le funzioni) in "math.h". Se si usano macro di stile non funzionali, qualsiasi tentativo di usare '(std :: sin) (x)' o '(mymath :: sin) (y)' verrebbe comunque manomesso da queste macro. –

2

Avete bisogno di includere le intestazioni math.h e CMATH direttamente nel file di intestazione? Se avete bisogno di, provare tra cui l'intestazione come questo:

namespace arbitrary_name 
{ 
    #include <math.h> 
} 

Questo conterrà tutte le definizioni math.h all'interno di un nuovo spazio dei nomi, in modo da non li userete accidentalmente altrove.

Questa non è la soluzione ideale. Forse c'è un modo migliore per farlo usando spazi dei nomi anonimi, ma la soluzione non mi è chiara.

+0

Funzionerà, ma solo se 'math.h' contiene solo codice C. Preferirei includere 'cmath', in modo che dichiari molte funzioni sovraccariche con lo stesso nome delle funzioni standard (es .:' double cos (double x); ',' float cos (float x); '...) . - Comunque penso che questo sia il meglio che posso fare ... – peoro

+0

The River, questo non funzionerà in quanto tutti i simboli esportati da quella lib non sono nello spazio dei nomi in cui inserisci l'intestazione. –

2

Sfortunatamente la soluzione più affidabile sarà quella di non utilizzare gli stessi nomi di funzioni della libreria standard. Fortunatamente i nomi delle funzioni standard sono concisi e fortemente abbreviati, quindi nomi come cosine(), sine(), exponent(), arctan() sarebbero unici (e probabilmente migliori) senza dover adornare il nome con prefissi maldestri.

In alternativa si potrebbe mantenere gli stessi nomi, ma li capitalizzare: Sin(), Cos(), Exp() ecc

+0

Ovviamente funzionerà , ma siccome mi dimentico di usare esplicitamente un determinato spazio dei nomi, sono sicuro che spesso dimenticherò di usare i miei nomi personalizzati per le funzioni standard. Tuttavia sarebbe più facile trovare dove uso nomi di funzioni standard ... – peoro

+0

Preferisco il nome completo piuttosto che giocare in lettere maiuscole. –

+0

@ Matthieu: Sono completamente d'accordo, è orribile ma potrebbe piacere ad alcuni. – Clifford

1

Scrivi alcune funzioni wrapper in un file separato.

#include <math.h> 

namespace my_wrapper 
{ 

float sin(float n) 
{ 
    return std::sin(float n); 
} 

}; 

O qualcosa del genere. E quindi utilizzare solo quelli negli altri file e non includere nemmeno o negli altri file soure. Sì, è un piccolo problema scrivere le funzioni di inoltro per tutti, ma è solo un lavoro e non ce ne sono molti ...

Con un moderno compilatore che collega la generazione del codice temporale e può essere in linea tra i file oggetto questo non dovrebbero essere inefficiente ...

+0

E i modelli? 'template PROMOTE (T1, T2) pow (T1 x, T2 y) {return std :: pow ((PROMOTE (T1, T2)) x, (PROMOTE (T1, T2)) y) ; } '? ('PROMOTE' è una macro che ho definito che utilizza i modelli per promuovere i tipi, ad esempio: PROMOTE (int, double) è double). – peoro

+0

@peoro: usa 'export'. – ybungalobill

+0

'export' non è C++ 0x standard. – peoro

0

mia risposta preferita di Clifford finora, ma c'è un'altra alternativa si potrebbe prevedere: modificare la intestazioni standard per questo progetto (solo).

Dovrebbe essere presente un'opzione con il compilatore di scelta per indicare dove si trova la libreria standard, pertanto è possibile duplicare l'STL nel progetto e modificare i file in modo che i nomi non validi non vengano più iniettati nello spazio dei nomi globale.

Si tratta di hacker, ma questo è l'unico modo che posso pensare, a corto di controllare il codice con uno script per qualsiasi occorrenza di cos/sin che non è qualificato (cioè immediatamente preceduto da ::).