Domanda

Ho il seguente codice che compila e funziona bene:

template<typename T>
T GetGlobal(const char *name);

template<>
int GetGlobal<int>(const char *name);

template<>
double GetGlobal<double>(const char *name);

Comunque voglio rimuovere il " default " funzione. Cioè, voglio fare tutte le chiamate a GetGlobal & Lt; t & Gt; dove 't' non è un int o un doppio un errore.

Ad esempio, GetGlobal < char > () dovrebbe essere un errore di tempo di compilazione.

Ho provato a cancellare la funzione predefinita, ma, come immaginavo, ho ricevuto molti errori. Quindi c'è un modo per " disabilitare " e consentire chiamate solo alle versioni specializzate della funzione?

Grazie!

È stato utile?

Soluzione

Per ottenere un errore di compilazione, implementalo come:

template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined

Se usi Boost potresti renderlo più elegante:

template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }

Lo standard C ++ garantisce che non esiste un tipo di questo tipo con dimensioni pari a 0, quindi verrà visualizzato un errore di compilazione.

Come sbi ha suggerito nei suoi commenti che l'ultimo potrebbe essere ridotto a:

template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }

Preferisco la prima soluzione, perché fornisce un messaggio di errore più chiaro (almeno in Visual C ++) rispetto agli altri.

Altri suggerimenti

Sebbene si tratti di una domanda vecchia e obsoleta, vale la pena notare che C++11 aveva risolto questo problema utilizzando le funzioni eliminate:

template<typename T>
T GetGlobal(const char *name) = delete;

template<>
int GetGlobal<int>(const char *name);

Aggiorna

Questo non verrà compilato in MacOS llvm 8. È dovuto a un difetto di 4 anni ancora sospeso (vedere questa segnalazione di bug ).

La seguente soluzione alternativa si adatterà al problema (usando un static_assert costrutto).

template<typename T>
T GetGlobal(const char *name) {
    static_assert(sizeof(T) == 0, "Only specializations of GetGlobal can be used");
}

template<>
int GetGlobal<int>(const char *name);

Aggiorna

Visual Studio 15.9 ha lo stesso bug. Usa la soluzione precedente per questo.

Se non lo implementi, otterrai almeno un errore del linker. Se desideri un errore di compilazione, puoi farlo con i modelli di classe:

template<typename T>
struct GlobalGetter;

template<>
struct GlobalGetter<int> {
  static int GetGlobal(const char *name);
};

template<>
struct GlobalGetter<double> {
  static double GetGlobal(const char *name);
};

template<typename T>
T GetGlobal(const char *name)
{
  return GlobalGetter<T>::GetGlobal(name);
}

Suggerirei di non fornire effettivamente un'implementazione, ma solo una nuda dichiarazione del metodo.

L'altra opzione sarebbe quella di utilizzare un'asserzione in fase di compilazione. Boost ha un certo numero di tali animali.

namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
                            boost::same_type<T, int> >));

Esiste anche la sua controparte della versione del messaggio, che sarebbe di aiuto.

Le seguenti sono tecniche alternative all'utilizzo di boost:

Dichiara un typedef con un nome dipendente

Funziona perché la ricerca del nome per DONT si verifica solo quando 'T' è stato sostituito. Questa è una versione simile (ma legale) dell'esempio fornito da Kirill

template <typename T>
T GetGlobal (const char * name) {
    typedef typename T::DONT CALL_THIS_FUNCTION;
}

Utilizza un tipo di ritorno incompleto

Questa tecnica non funziona per le specializzazioni, ma funzionerà per i sovraccarichi. L'idea è che è legale dichiarare una funzione che restituisce un tipo incompleto, ma non chiamarla:

template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top