Domanda

Tipo di domanda a caso ...

Quello che sto cercando è un modo per esprimere un'operazione di cast che utilizza un operatore definito dell'istanza di classe da cui eseguo il casting e genera un errore di compilazione se non esiste un operatore di cast definito per il tipo . Quindi, per esempio, quello che sto cercando è qualcosa di simile:

template< typename RESULT_TYPE, typename INPUT_TYPE >
RESULT_TYPE operator_cast( const INPUT_TYPE& tValue )
{
    return tValue.operator RESULT_TYPE();
}

// Should work...
CString sString;
LPCTSTR pcszString = operator_cast< LPCTSTR >( sString );

// Should fail...
int iValue = 42;
DWORD dwValue = operator_cast< DWORD >( iValue );

Nota a margine interessante: il codice sopra riportato blocca il compilatore C ++ VS2005 e non viene compilato correttamente nel compilatore C ++ VS2008 a causa di quello che immagino sia un bug del compilatore, ma si spera che dimostri l'idea.

Qualcuno sa come ottenere questo effetto?

Modifica: più motivazioni, per spiegare perché potresti usarlo. Supponi di avere una classe wrapper che dovrebbe incapsulare o sottrarre un tipo e che stai lanciando sul tipo incapsulato. Potresti usare static_cast & Lt; & Gt ;, ma potrebbe funzionare quando vuoi che fallisca (es: il compilatore sceglie un operatore che è autorizzato a convertire nel tipo che hai richiesto, quando volevi un errore perché tale operatore non è presente).

Certamente è un caso insolito, ma è fastidioso che non riesca ad esprimere esattamente quello che voglio che il compilatore faccia in una funzione incapsulata ... da qui la domanda.

È stato utile?

Soluzione

Il codice che hai pubblicato funziona con il compilatore Cameau (che di solito è una buona indicazione che è C ++ valido).

Come sai un cast valido è composto da non più di un cast definito dall'utente, quindi una possibile soluzione a cui stavo pensando era l'aggiunta di un altro cast definito dall'utente definendo un nuovo tipo nel modello di cast e avendo un asserzione statica che nessun cast è disponibile dal nuovo tipo al tipo di risultato (usando boost is_convertible ), tuttavia ciò non distingue tra operatori di cast e costruttori di cast (ctor con un argomento) e consente l'esecuzione di cast aggiuntivi (ad es. da void* a bool). Non sono sicuro che fare una distinzione tra operatori di cast e costruttori di cast sia la cosa corretta da fare, ma è quello che afferma la domanda.

Dopo un paio di giorni rimuginando su questo mi ha colpito, puoi semplicemente prendere l'indirizzo dell'operatore del cast. Questo è leggermente più facile a dirsi che a farsi a causa del puntatore peloso di C ++ alla sintassi dei membri (mi ci è voluto molto più tempo del previsto per farlo bene). Non so se funziona su VS2008, l'ho controllato solo su Cameau.

template< typename Res, typename T>
Res operator_cast( const T& t )
{
    typedef Res (T::*cast_op_t)() const;
    cast_op_t cast_op = &T::operator Res;
    return (t.*cast_op)();
}

Modifica: ho avuto la possibilità di testarlo su VS2005 e VS2008. Le mie scoperte differiscono da quelle del poster originale.

  • Su VS2008 la versione originale sembra funzionare bene (come la mia).
  • Su VS2005 la versione originale si arresta in modo anomalo durante la trasmissione da un tipo incorporato (ad es. casting int in int) solo dopo aver fornito un errore di compilazione che non sembra poi così grave e la mia versione sembra funzionare in tutti i casi.

Altri suggerimenti

Utilizzando un costruttore di conversione contrassegnato esplicito è come impedirebbe al compilatore di consentire ai tipi convertiti implicitamente di inizializzare la classe wrapper.

Dato che i messaggi di errore del compilatore relativi al modello sono di solito un problema completo da svelare, se non ti dispiace specificare ogni conversione puoi far sì che il compilatore emetta un messaggio più istruttivo nel caso di fallimento fornendo anche una definizione di modello predefinita. Questo utilizza il fatto che il compilatore tenterà solo di compilare il codice nei template che viene effettivamente invocato.

#include <string>

// Class to trigger compiler warning   
class NO_OPERATOR_CONVERSION_AVAILABLE
{
private:
   NO_OPERATOR_CONVERSION_AVAILABLE(){};
};

// Default template definition to cause compiler error
template<typename T1, typename T2> T1 operator_cast(const T2&)
{
   NO_OPERATOR_CONVERSION_AVAILABLE a;
   return T1();
}

// Template specialisation
template<> std::string operator_cast(const std::string &x)
{
   return x;
}

sembra che tu voglia la specializzazione del modello, qualcosa del genere farebbe:

/* general template */
template<typename T1, typename T2> T1 operator_cast(const T2 &x);

/* do this for each valid cast */
template<> LPCTSTR operator_cast(const CString &x) { return (LPCTSTR)x; }

EDIT: come notato in un altro post, puoi inserire qualcosa nella versione generale per darti un messaggio di errore più utile se viene eseguito un cast non supportato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top