L'apparecchio di prova è a un collegamento di off-site ed è variato dal tuo post originale, così ho copierà testualmente il test-set di cui sto parlando qui:
static_assert(is_explicitly_convertible< double, double >::value, "1");
static_assert(is_explicitly_convertible< double &, double >::value, "2");
static_assert(is_explicitly_convertible< double const, double >::value, "3");
static_assert(is_explicitly_convertible< double const &, double >::value, "4");
static_assert(is_explicitly_convertible< double, double const & >::value, "5");
static_assert(is_explicitly_convertible< double &, double const & >::value, "6");
static_assert(is_explicitly_convertible< double const, double const & >::value, "7");
static_assert(is_explicitly_convertible< double const &, double const & >::value, "8");
static_assert(!is_explicitly_convertible< double, double & >::value, "9"); // not a ref
static_assert(is_explicitly_convertible< double &, double & >::value, "10");
static_assert(!is_explicitly_convertible< double const, double & >::value, "11");
static_assert(!is_explicitly_convertible< double const &, double & >::value, "12");
static_assert(is_explicitly_convertible< double, double const >::value, "13");
static_assert(is_explicitly_convertible< double &, double const >::value, "14");
static_assert(is_explicitly_convertible< double const, double const >::value, "15");
static_assert(is_explicitly_convertible< double const &, double const >::value, "16");
static_assert(is_explicitly_convertible< AA const &, A const & >::value, "=&1.a");
static_assert(is_explicitly_convertible< CC const &, C const & >::value, "=&1.b");
static_assert(is_explicitly_convertible< BB const &, B const & >::value, "=&1.c");
static_assert(!is_explicitly_convertible< AA const &, A & >::value, "&1.a");
static_assert(!is_explicitly_convertible< CC const &, C & >::value, "&1.b");
static_assert(!is_explicitly_convertible< BB const &, B & >::value, "&1.c");
static_assert(is_explicitly_convertible< AA const, A const & >::value, "=1.a");
static_assert(is_explicitly_convertible< CC const, C const & >::value, "=1.b");
static_assert(is_explicitly_convertible< BB const, B const & >::value, "=1.c");
//static_assert(!is_explicitly_convertible< AA const, A >::value, "=2.a"); // ???????????????
//static_assert(!is_explicitly_convertible< CC const, C >::value, "=2.b");
//static_assert(!is_explicitly_convertible< BB const, B >::value, "=2.c");
static_assert(!is_explicitly_convertible< AA const, A & >::value, "=3.a"); // good!
static_assert(!is_explicitly_convertible< CC const, C & >::value, "=3.b"); //
static_assert(!is_explicitly_convertible< BB const, B & >::value, "=3.c"); //
static_assert(!is_explicitly_convertible< AA const, A && >::value, "=4.a"); // not interesting
static_assert(!is_explicitly_convertible< CC const, C && >::value, "=4.b"); //
static_assert(!is_explicitly_convertible< BB const, B && >::value, "=4.c"); //
static_assert(!is_explicitly_convertible< AA const, B const & >::value, "=5.a");
static_assert(!is_explicitly_convertible< AA const, C const & >::value, "=5.b");
static_assert(!is_explicitly_convertible< BB const, A const & >::value, "=5.c");
static_assert(!is_explicitly_convertible< BB const, C const & >::value, "=6.a");
static_assert(!is_explicitly_convertible< CC const, A const & >::value, "=6.b");
static_assert(!is_explicitly_convertible< CC const, B const & >::value, "=6.c");
static_assert(!is_explicitly_convertible< AA const, B & >::value, "=7.a");
static_assert(!is_explicitly_convertible< AA const, C & >::value, "=7.b");
static_assert(!is_explicitly_convertible< BB const, A & >::value, "=7.c");
static_assert(!is_explicitly_convertible< BB const, C & >::value, "=8.a");
static_assert(!is_explicitly_convertible< CC const, A & >::value, "=8.b");
static_assert(!is_explicitly_convertible< CC const, B & >::value, "=8.c");
static_assert(!is_explicitly_convertible< AA const, B >::value, "=9.a"); // very subtle moment (see class AA above)
static_assert(!is_explicitly_convertible< AA const, C >::value, "=9.b");
static_assert(is_explicitly_convertible< BB const, A >::value == std::is_constructible< A, A && >::value, "=9.c"); // (see class BB above)
static_assert(!is_explicitly_convertible< BB const, C >::value, "=10.a");
static_assert(!is_explicitly_convertible< CC const, A >::value, "=10.b");
static_assert(!is_explicitly_convertible< CC const, B >::value, "=10.c");
static_assert(is_explicitly_convertible< AA, A & >::value, "~1.a");
static_assert(is_explicitly_convertible< CC, C & >::value, "~1.b");
static_assert(is_explicitly_convertible< BB, B & >::value, "~1.c");
//static_assert(!is_explicitly_convertible< AA, A >::value, "~2.a"); // ???????????????
//static_assert(!is_explicitly_convertible< CC, C >::value, "~2.b");
//static_assert(!is_explicitly_convertible< BB, B >::value, "~2.c");
static_assert(is_explicitly_convertible< AA, A const & >::value, "~3.a"); // convertible
static_assert(is_explicitly_convertible< CC, C const & >::value, "~3.b"); //
static_assert(is_explicitly_convertible< BB, B const & >::value, "~3.c"); //
static_assert(!is_explicitly_convertible< AA, B const & >::value, "~4.a");
static_assert(!is_explicitly_convertible< AA, C const & >::value, "~4.b");
static_assert(!is_explicitly_convertible< BB, A const & >::value, "~4.c");
static_assert(!is_explicitly_convertible< BB, C const & >::value, "~5.a");
static_assert(!is_explicitly_convertible< CC, A const & >::value, "~5.b");
static_assert(!is_explicitly_convertible< CC, B const & >::value, "~5.c");
static_assert(std::is_convertible< double, double const & >::value, "5*");
static_assert(!std::is_convertible< double, double & >::value, "9*");
Se usufruire di gcc 4.7.2 (e forse anche prima, non ho controllato), allora il C++ 11 libreria standard risolve il problema:
std::is_explicitly_convertible<From,To>
è definito in <type_traits>
Tuttavia, si sarebbe poi essere avvalendosi di un error in quella versione del C++ Standard Library 11. Questo modello di tratto non avrebbe dovuto essere lì, perché è stato rimosso dallo standard in base a N3047 (2010).
Se siete a GCC 4.8.1 (o forse 4.8, non ho controllato), allora questo tratto non è più nella biblioteca, e se lo vuoi devi ancora rotolare il proprio.
Ma sarebbe solo umano per ispezionare la definizione di gcc 4.7.2 di <type_traits>
per un inizio, e facendo che rivela che il realizzatore GNU considerato il tratto di essere altro che l'inverso di std::is_constructible<To,From>
:
/// is_explicitly_convertible
template<typename _From, typename _To>
struct is_explicitly_convertible
: public is_constructible<_To, _From>
{ };
Si può anche pensare: Ma naturalmente.
Allora, perché non sarà che fare per essere in corso con? N3047 spiega:
La domanda rimanente è, in che modo il tratto interessato anche is_explicitly_convertible
deve essere riparato.Le scelte di base sono:
- Fix
is_explicitly_convertible
restituendo l'espressione static_cast corrente, non è più rendendo is_explicitly_convertible
dipende is_constructible
.
- Rimuovere
is_explicitly_convertible
dallo standard.
La prima scelta è stata presa in considerazione, ma si è scoperto che esiste una comprensione abbastanza diversa di ciò che "esplicitamente convertibile" dovrebbe in realtà significare. Mentre alcuni ritengono che static_cast
esprima correttamente questo, altri hanno creduto che il is_constructible
fisso fornisse anche un significato migliore per is_explicitly_convertible
. Pertanto, questo documento consiglia di rimuovere is_explicitly_convertible
dalla bozza di lavoro. Questo non dovrebbe essere pericoloso ora, perché nulla dipende ancora da quella definizione speciale. E se risultasse che il tratto sarebbe comunque utile, potrebbe essere aggiunto in un'altra revisione dello standard.
non c'era bug noto in tale definizione, ma non vi erano viste opposte sul fatto che il significato di "esplicitamente convertibile" che codifica è quella giusta: -
- D1)
From
è esplicitamente convertibile To
= df To
è costruibile da From
- D2)
From
è esplicitamente convertibile in To
= df From
può essere gettato in modo statico a To
Non voglio discutere di questa polemica (non ho ancora elaborato quale sia la differenza, io stesso) ma vi suggerisco che basta pagate i vostri soldi e fare la vostra scelta.
Se si preferisce D1), si può semplicemente prendere la definizione del tratto da gcc 4.7.2 <type_traits>
, come sopra.
Se sei a favore D2, allora si potrebbe plagiare e adattare la definizione di std::is_convertible<From,To>
da gcc 4.8.1 <type_traits>
. Questa definizione richiama le funzioni ausiliarie interne da rintracciare.L'adattamento si vorrebbe sarebbe quello di cambiare il test SFINAE per From
può essere implicitamente in To
ad un test per From
può essere static_cast
a To
; e ciò significherebbe sostituzione:
template<typename _From1, typename _To1>
static decltype(__test_aux<_To1>(std::declval<_From1>()), __one())
__test(int);
con:
template<typename _From1, typename _To1>
static decltype(__test_aux<_To1>(static_cast<_To1>(std::declval<_From1>())), __one())
__test(int);
Una versione ridotta di questa definizione (ignorando questi casi come From
essere void
e To
essere un tipo di funzione o array) che farebbe per i tipi che vengono testati nelle vostre static_assert
s:
template<typename From, typename To>
struct is_explicitly_convertible
{
template<typename T>
static void f(T);
template<typename F, typename T>
static constexpr auto test(int) ->
decltype(f(static_cast<T>(std::declval<F>())),true) {
return true;
}
template<typename F, typename T>
static constexpr auto test(...) -> bool {
return false;
}
static bool const value = test<From,To>(0);
};
Sia la definizione D1 o il cut-down definizione D2 sostiene tutte 63 le tue static_assert
s. (I compilata con g ++ 4.7.2 e 4.8.1, -g;-O0;-Wall;-std=c++11
, e anche con il -std=gnu++1y
che un lavoratore dipendente)
Il tuo più recente soluzione dimostra che hai fatto la tua strada per la scuola D2, con un diverso stile di implementazione.
Dei due, finché non trovo qualcosa che non va, io preferirei la definizione D1, come da gcc 4.7.2, solo perché è molto più semplice e, in particolare, è un derivato banale di std::is_constructible
.
forse sono fraintendimento della domanda, ma si può fare un 'dynamic_cast (FROM & val)', si getterà 'std :: bad_cast' se la conversione non è ammissibile. –
@ H2CO3 Si supponga, tale questione è di circa compilazione problema di tempo. – Orient
come si vuole verificare la presenza di un operatore conversione esplicita, il vostro compito sembra ridursi a [determinare se una classe T ha una funzione di membro con una data di firma] (http://stackoverflow.com/q/87372/1362568). Ci sono molte risposte là, tra cui uno dei miei. –