Mi arrendo, aiutaci a spiegare questo comportamento. L'esempio che presentiamo di seguito è il più semplice a cui potrei pensare, ma riassume il problema (usando g ++ 4.9.2 su Cygwin con C++ 14 abilitato). Voglio creare una classe che si comporterà come std::mem_fn
. Qui è la mia classe:.Il typedef interno cambia in base alla classe genitore
template <class R, class T, R(T::*P)() const >
struct property {
static R get(const T& t) {
return (t.*P)();
}
};
dove R
è il tipo di ritorno e T
è il tipo di oggetto sono interessanti nel parametro terzo modello è un puntatore a funzione membro. Fin qui tutto bene.
ho quindi creare una semplice classe che detiene un intero come segue
class data_class {
public:
unsigned get_data() const {
return m_data;
}
private:
unsigned m_data;
};
Questa è la classe che verrà utilizzato nella classe property
mostrato in precedenza.
Ora creare due classi che ereditano da data_class
come segue
struct my_classA
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
//same as my_classA, only templated
template <int I>
struct my_classB
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
Hanno la stessa identica typedef interna, ma my_classB
è basato su modelli. Ora i seguenti tipi dovrebbero in teoria essere lo stesso:
using target_t = property<unsigned, data_class, &data_class::get_data>;
using test1_t = typename my_classA::data;
using test2_t = typename my_classB<1>::data;
Tuttavia il mio compilatore dice che solo test1_t
e target_t
sono gli stessi. Il tipo dedotto per test2_t
è apparentemente
property<unsigned int, data_class, (& data_class::get_data)> >
dove questo tipo ha queste staffe intorno al puntatore a funzione membro. Perché lo test2_t
non è lo stesso di target_t
? Ecco il codice completo nel caso in cui tu voglia provarlo sul tuo sistema. Ogni aiuto è molto apprezzato.
#include <type_traits>
class data_class {
public:
unsigned get_data() const {
return m_data;
}
private:
unsigned m_data;
};
//takes return type, class type, and a pointer to member function
//the get function takes an object as argument and uses the above pointer to call the member function
template <class R, class T, R(T::*P)() const >
struct property {
static R get(const T& t) {
return (t.*P)();
}
};
struct my_classA
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
//same as my_classA, only templated
template <int I>
struct my_classB
: public data_class {
using data = property<unsigned, data_class, &data_class::get_data>;
};
//used to produce informative errors
template <class T>
struct what_is;
//all 3 types below should, in theory, be the same
//but g++ says that test2_t is different
using target_t = property<unsigned, data_class, &data_class::get_data>;
using test1_t = typename my_classA::data;
using test2_t = typename my_classB<1>::data;
static_assert(std::is_same<target_t, test1_t>::value, ""); //this passes
static_assert(std::is_same<target_t, test2_t>::value, ""); //this does not
int main() {
what_is<test1_t> t1;
what_is<test2_t> t2;
}
Provare effettivamente usando 'test2_t' (come dichiarare una variabile di quel tipo) per ottenere * molto * messaggi confusi:" errore: '& data_class :: get_data' non è un argomento modello valido per tipo 'unsigned int (data_class: : *)() const '"," errore: deve essere un puntatore-membro del modulo' & X :: Y '". – hvd
Funziona in GCC <= 4.8 e in Clang. Sembra essere una regressione in 4.9+. –
@ T.C: Grazie per questo. Potete fornire un link al bug report, per favore? Inseriscilo anche come risposta in modo che io possa accettarlo :) – linuxfever