2013-01-21 6 views
8

Abbiamo riscontrato un problema nel porting del nostro codice alla versione meno recente 2010 di VC++.Crea puntatore al membro per il tipo di valore della mappa in vc2010

I problemi è causato dalla realizzazione di mappa in VC che si traduce in un derivato a base conversione di un pointer-to-member in un non-type-argument venga richiesto:

#include <map> 
#include <algorithm> 

template <typename MapValueType, int MapValueType::*var> 
bool f (MapValueType const & v); 

int main() 
{ 
    typedef std :: map<int, int> MapType; 
    MapType m; 
    std :: find_if (m.begin() 
     , m.end() 
     , f<MapType::value_type, & MapType::value_type::second>); 
} 

Il seguente messaggio viene generato:

La conversione standard da puntatore a membro di base a puntatore-membro di derivato non viene applicata per gli argomenti modello file.cc (x): errore C2973: 'f': argomento modello non valido 'int std :: _ Pair_base < _Ty1, _Ty2> :: * '

Così sembra che l'attuazione di value_type nel std::map ha la coppia in una classe base.

Qualche idea su come risolvere questo e mantenere il pointer-to-member come non-type-argument?

La nostra unica opzione è modificare la struttura in modo che f sia un con un membro pointer-to-member?

+1

forse una domanda stupida, ma perché è necessario passare quel puntatore al membro? –

+0

che cosa è con gli spazi che circondano '' 'e altri token lessicali? – TemplateRex

+0

sì, giusto per chiarire la domanda precedente, perché più semplice 'template bool f (MapItemType const & v);' non funziona per te? –

risposta

3

A condizione che il codice dovrebbe compilare IMO (e lo fa su GCC 4.7. 2 e Clang 3.2), credo che il tuo design sia inutilmente intricato. A pair ha solo due variabili membro, quindi si accederà al primo o al secondo.

Non vedo la necessità di un oggetto funtore: basta usare un argomento del modello booleano per determinare se il codice deve funzionare su first o sulla variabile membro second. Ecco una possibilità:

#include <map> 
#include <algorithm> 

template <typename MapValueType, bool first> 
bool f (MapValueType const & p) 
{ 
    auto& v = (first) ? p.first : p.second; 
    // ... do your work on v ...  
} 

int main() 
{ 
    typedef std :: map<int, int> MapType; 
    MapType m; 

    // Will work on the `first` member 
    std::find_if(m.begin(), m.end(), f<MapType::value_type, true>); 

    // Will work on the `second` member 
    std::find_if(m.begin(), m.end(), f<MapType::value_type, false>); 
} 

Se davvero non si può modificare il codice cliente né il codice all'interno della funzione f(), allora si potrebbe andare per questa specifica-VS2010 mod:

// Add "_MyBase" here... works, but ugly IMO 
template <typename MapValueType, int MapValueType::_Mybase::* var> 
bool f(MapValueType const & v); 

// And the client side could stay unchanged... 
int main() 
{ 
    typedef std :: map<int, int> MapType; 
    MapType m; 
    std::find_if(
     m.begin(), 
     m.end(), 
     f<MapType::value_type, &MapType::value_type::second> 
     ); 
} 

Infine, se il il codice deve compilare su altre piattaforme e tutti i vincoli sulla non modificabilità del codice della funzione e del client ancora in attesa, quindi è possibile definire una macro del preprocessore che si espande a _Mybase:: per VS2010 e alla stringa vuota per altri compilatori.

+0

Grazie per la risposta (+1). Parte della motivazione per porre la domanda è stata presa di sorpresa dal fatto che il codice non funziona più. Se questo faceva parte di un'API che non può cambiare, come lo affronteresti? –

+0

@RichardCorden: aggiornata la risposta con una soluzione (sinceramente non ci andrei, perché è fortemente specifica per VS2010, ma ... beh, spetta a te alla fine) –

+0

Dovresti aggiungere il bool o il membro prima di percorrere questa strada - il codice deve essere compilato anche con g ++. –

4

Perché insisti a mantenere il puntatore al membro come parametro/argomento del modello non di tipo?

In ogni caso, penso che si potrebbe usare questo, se si può essere limitato a Visual Studio 2010 o compilatori con decltype()

template <typename Class, typename Type> 
Class 
get_class_type (Type Class:: *); 
//... 
it = std::find_if(m.begin(), m.end(), 
    f<decltype(get_class_type(&MapType::value_type::second)), &MapType::value_type::second>); 
+1

La risposta breve è perché se posso, preferirei non dover modificare il codice che so funziona, o in altre parole Lazyness! –

+0

+1 per onestà! :) – wilx

+0

Solo per dire che ho contrassegnato Andy come la risposta, ma questo si basa solo su quello che soddisfa il mio ambiente di sviluppo. Uno dei compilatori che usiamo è g ++ 4.2.4 che non ha decltype. Ma la tua soluzione risolverà il problema da ora in poi. –

Problemi correlati