2014-09-03 13 views
11

Sto tentando di identificare in fase di compilazione se una funzione viene mai chiamata. In particolare, voglio lanciare un fallimento asserzione statico se si tratta di:Come verificare in fase di compilazione se viene chiamata una funzione

template <typename T> 
auto Function(T value) -> std::enable_if<someCondition, int> 
{ 
    // this is the function I want to call 
} 

template <typename... T> 
int Function(T...) 
{ 
    // This function should never be called, instead I want 
    // a compile-time failure if this is called, because it 
    // means the above function wasn't successfully resolved. 
} 

Il motivo che voglio fare questo è perché il fallimento di chiamare correttamente Function() con i risultati corrette condizioni in migliaia di righe di messaggi di errore del compilatore, nessuno di cui sono molto utili a chiunque non abbia familiarità con la base di codice.

Il motivo per cui non voglio mettere un static_assert in Function è perché abbiamo molte di queste funzioni, e abbiamo i mezzi, invece di generare le versioni Catch-all tramite macro, che eviterebbe la crescita non necessaria del codice-base durante la produzione di messaggi di errore più utili.

Questo può essere fatto?

+0

Non capisco dalla tua domanda perché non vuoi un 'static_assert'. Cerchi di spiegarlo, ma non capisco la tua spiegazione. Se le versioni catch-all sono generate da macro, perché un 'static_assert' non può essere generato da una macro? – hvd

+0

@Arman il mio commento ha l'intenzione di mostrare che il tuo titolo è un falso. – 101010

+0

@hvd no, perché la macro si trova in una posizione diversa e la 'Funzione' che desidero chiamare è * non * generata da una macro. Il motivo per cui voglio farlo in questo modo è perché la macro (che è da qualche altra parte) può ancora generare la funzione catch-all. – arman

risposta

14

Sulla base delle osservazioni sulla tua domanda, non si vuole un static_assert qui:

template <typename T> 
auto Function(T value) -> std::enable_if<someCondition, int> 
{ 
    // this is the function I want to call 
} 

... ma non c'è niente di sbagliato in realtà con un static_assertqui:

template <typename... T> 
struct dependent_false { static constexpr bool value = false; }; 

template <typename... T> 
int Function(T...) 
{ 
    static_assert(dependent_false<T...>::value, "you are passing the wrong arguments!"); 
} 

Come hai giustamente notato, un semplice static_assert(false, "..."); fallirebbe al momento della definizione del modello. Per ottenere qualcosa che non funziona al momento dell'istanziazione, è necessaria un'espressione dipendente e la struttura helper dependent_false è un modo semplice per ottenere qualcosa che dipenda dal tipo, sarà sempre false, ma non può essere assunto dal compilatore per veramente sempre false: il compilatore non può escludere l'aggiunta di specializzazioni parziali per rendere dependent_false<...>::valuetrue per qualche tipo.


Guardando indietro a questa vecchia domanda, potrebbe esserci una risposta molto più semplice: contrassegnare il sovraccarico come cancellato.

template <typename T> 
auto Function(T value) -> std::enable_if<someCondition, int> 
{ 
    // this is the function I want to call 
} 

template <typename... T> 
int Function(T...) = delete; 

Questo non è esattamente la stessa cosa, poiché questo consente al chiamante di verificare la buona formulazione di esempio Function(int, int) invece di forzare un errore, ma è più leggibile, e in genere si desidera che il comportamento esatto di non ottenere un errore a meno che la funzione non sia effettivamente utilizzata, non meramente referenziata.

+1

Perché non fare 'static_assert (false," ... ")'? – 0x499602D2

+2

@ 0x499602D2 Perché ciò può (e in genere avviene) non riuscire al momento della definizione del modello, anziché al tempo di istanziazione del modello. – hvd

+0

Ottima risposta, grazie :) È un peccato che l'STL non fornisca 'dependent_false'! – arman

Problemi correlati