2009-06-04 19 views
7

C'è un modo per verificare in fase di compilazione se qualche classe ha un costruttore con determinati argomenti? ?Controllare la firma del costruttore della classe di compilazione

Ad esempio:

class foo { 
    foo(std::string &s) { 
    } 
}; 

voglio controllare al momento della compilazione che costruttore con std :: string & sempre definito. Forse boost fornisce tale funzionalità?

+0

Intendi senza cercare di creare oggetti? – Naveen

+1

Se si utilizza questo costruttore mentre non è definito, il compilatore genererà un errore. Se non lo usi, allora perché vuoi che sia presente? –

+0

L'interessante testcase per ogni controllo proposto è std :: string stesso. – MSalters

risposta

3

Se si ha realmente bisogno, è possibile aggiungere questa funzione:

static void _dummy() { std::string s; foo f(s); } 

Senza il vostro costruttore, la compilazione fallirà. Nota: il tuo costruttore è privato. Se è apposta, allora _dummy dovrebbe essere all'interno della classe. Altrimenti, puoi averlo fuori dalla classe.

Inoltre, è possibile templatize o addirittura renderlo una macro, se questo accade molto nel codice.

Ma a dire la verità, sembra ancora come un hack. Sei sicuro di averne bisogno?

0

cosa si sta chiedendo suona un po 'come una prova di unità. Vorrei scaricare qualcosa come cppunit e integrarlo nella tua compilation.

Qualsiasi test di unità che scrivete saranno costruiti/eseguiti in fase di compilazione. Vedere Unit Testing per ulteriori informazioni.

+0

I test unitari non sono realmente in fase di compilazione, e questo è stato chiesto molto esplicitamente. Ci sono già 2 soluzioni che dimostrano che è del tutto possibile. – MSalters

+0

I test delle unità non sono un controllo del tempo di compilazione, ma possono essere impostati per l'esecuzione quando si compila il codice. Questo ti dà quello che probabilmente stai cercando comunque, che è un modo per convalidare i contratti funzionali e le ipotesi sul tuo codice. C'è una ragione per cui questo deve accadere in fase di compilazione? –

0

Se avete bisogno di questo tipo di controlli, probabilmente bisogno di qualche altro momento della compilazione il controllo

vi suggerisco di dare un'occhiata per amplificare il concetto controllo biblioteca (la documentazione è here). Puoi trovare documentazione, classi e macro che possono aiutarti.

3

Se si sta cercando di verificare se foo è costruibile da una stringa, è possibile utilizzare boost::is_convertible.

Ad esempio:

BOOST_STATIC_ASSERT((boost::is_convertible<std::string, foo>::value)); 
2

con Verifica Concetto in spinta 1.39:

#include <boost/concept_check.hpp> 

class foo_c 
{ 
public: 
    foo_c(std::string& s) 
    {} 
}; 

template<typename T> 
class algo_c 
{ 
BOOST_CONCEPT_ASSERT((boost::Convertible<std::string,T>)); 
public: 
    algo_c() 
    {} 
}; 

Rimozione o cambiando il costruttore di risultato foo_c il seguente errore di compilazione:

error C2440: 'initializing' : cannot convert from 'std::string' to 'foo_c'

EDIT: Che può essere fatto funzionare con costruttore esplicito con un homem ade controllo concetto:

template <typename T> 
struct HasTheRightConstructor 
{ 
    BOOST_CONCEPT_USAGE(HasTheRightConstructor) 
    { 
     std::string v; 
     T j(v); 
    } 
}; 
+1

Questo metodo non funziona per i costruttori espliciti. Funziona solo per i costruttori con 1 argomento non predefinito. Non funziona, se l'operatore di conversione è definito da "std :: string" a T –

+0

Punto buono. Modificato in modo che funzioni con il ctor esplicito. Non so come fare per abbinare un prototipo preciso (non posso fare una risposta da MSalters per compilare –

6

Il modo più comune per controllare se esiste una funzione specifica è quella di prendere il suo indirizzo e assegnazione a una variabile dummy. Questo è molto più preciso dei test menzionati finora, perché verifica la firma della funzione esatta. E la domanda era specificamente su string& nella firma, quindi non-const e quindi presumibilmente modificando la stringa.

Tuttavia, in questo caso non è possibile utilizzare il trucco take-the-address-and-assign-it: i costruttori non hanno indirizzi. Allora, come controlli la firma? Semplicemente: fai amicizia con una lezione finta.

template<typename T> 
class checkSignature_StringRef { 
    friend T::T(string&); 
}; 

Anche questo è un controllo molto preciso: non sarà nemmeno corrispondere costruttori simili come foo::foo(std::string &s, int dummy = 0).

+0

Che non si compila con VC8: la classe contiene l'override esplicito 'T :: {ctor}' ma non deriva da un'interfaccia che contiene la dichiarazione di funzione –

+0

nota il rapporto sui difetti qui: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#215 –

+0

arresto anomalo su gcc3! Errore di compilazione su gcc4 ... che il metodo sembra buono, ma sarei felice di sapere che chiunque altro lo ha compilato ... –

1

Mi è venuto in mente un problema simile che volesse inoltrare i costruttori alla classe base quando gli argomenti sono compatibili e fare qualcos'altro quando no.

ecco un tratti generalizzate a lavorare su MSVC 2013 (richiede C++ 11 roba):

namespace detail { 
    template<class type,class...Args> 
    class constructible_from 
    { 
     template<class C> 
     static C arg(); 

     template <typename U> 
     static boost::mpl::true_ constructible_test(U *, decltype(U(arg<Args>()...)) * = 0); 
     static boost::mpl::false_ constructible_test(...); 

    public: 

     typedef decltype(constructible_test(static_cast<type*>(nullptr))) result; 

    }; 
} // namespace detail 

template<class type> 
struct constructible 
{ 
    template<class...Args> 
    struct from : 
     detail::constructible_from<type,Args...>::result {}; 
}; 

Ecco un esempio di utilizzo tratti, lascio il enable_if applicazione come un esercizio: D:

struct b{}; 
struct c{}; 
struct d : c{}; 

struct a 
{ 
    a() {} 
    a(a &) {} 
    a(b,c) {} 
    a(c) {} 
}; 


static_assert(
    constructible<a>::from<>::value, 
    "a()" 
); 
static_assert(
    constructible<a>::from<a&>::value, 
    "a(a&)" 
); 
static_assert(
    ! constructible<a>::from<const a&>::value, 
    "a(const a&)" 
); 
static_assert(
    constructible<a>::from<b,c>::value, 
    "a(b,c)" 
); 
static_assert(
    ! constructible<a>::from<b>::value, 
    "a(b)" 
); 
static_assert(
    constructible<a>::from<c>::value, 
    "a(c)" 
); 
static_assert(
    constructible<a>::from<d>::value, 
    "a(d)" 
); 
Problemi correlati