2016-04-06 20 views
9

Ho il seguente modello non-type:sovraccarico operatore di assegnazione copia per uno struct membro di un non-modello di tipo struct

template<size_t MAX_SIZE> 
struct Path{ 
    struct Point{ 
     float x; 
     float y; 
     } 
    }; 
    Point segment[MAX_SIZE]; 
}; 

Se ora dichiaro due percorsi differenti, non può assegnare elementi dei diversi segmenti gli uni agli altri, come le struct possono avere la stessa struttura, ma sono di diverso tipo:

Path<10> path_a ; 
Path<30> path_b ; 
path_a.segment[0].x = 1; 
path_a.segment[0].y = 2; 
path_b.segment[0] = path_a.segment[0]; // <- error C2679 in Visual Studio) 

Certo, se mi separo la definizione di sito e la via, la cessione avrebbe funzionato:

struct Point{ 
     float x; 
     float y; 
     }; 

template<size_t MAX_SIZE> 
struct Path{ 
    Point segment[MAX_SIZE]; 
}; 

Ma non è quello che voglio (questo è solo un MWE), quindi mi chiedevo come sovraccaricare l'operatore di assegnazione delle copie per farlo funzionare. Ho provato numerose varianti, ad esempio:

template<size_t MAX_SIZE> 
struct Path{ 
    struct Point{ 
     float x; 
     float y; 
     template<size_t OTHER_SIZE> 
     Point & operator = (const typename Path<OTHER_SIZE>::Point & that) 
     { 
      x = that.x; 
      y = that.y; 
      return *this; 
     } 
    }; 
    Point segment[MAX_SIZE]; 
}; 

ma ottengo sempre lo stesso errore. Quindi la mia domanda è: è possibile sovraccaricare = in un modo che consenta l'assegnazione del seguente modulo senza modificare il layout delle mie strutture?

path_b.segment[0] = path_a.segment[0]; 
+1

solo per assicurarsi che non si è X-Y'ing questo, si può elaborare il motivo per cui * * Punto di ogni percorso deve essere un tipo distinto, ma ancora assegnabile tra loro? –

+0

@ MarkB, questa è una domanda irrilevante. La domanda è valida per conto proprio. Assegnare strutture interne a diversi modelli esterni è una cosa valida per conto proprio. – SergeyA

+0

@ MarkB: La ragione principale è che sono un po 'testardo e volevo davvero sapere se c'è un modo per farlo funzionare. Inoltre, una soluzione alternativa potrebbe essere possibile per il semplice esempio presentato qui, ma non nel caso generale, poiché, ad esempio, potrebbe richiedere più modifiche in una base di codice esistente. – magnetometer

risposta

5

Sì, tale configurazione è possibile. Al centro, è necessario un modello di operatore di assegnazione che accetta tutti i tipi:

template<class T> 
Point & operator = (const T & that) 

Come una soluzione di base, questo sarebbe sufficiente. Funzionerà ora con tutti i tipi che hanno membri x e di tipi compatibili e producono un messaggio di errore (solitamente) brutto per tipi che non lo fanno.

Se questo è abbastanza buono per te, abbiamo finito.

Se si dispone di altri sovraccarichi dell'operatore di assegnazione, è probabile che si desideri disattivare selettivamente il modello. Per questo, è necessario strumento le Point classi e utilizzare SFINAE:

template<size_t MAX_SIZE> 
struct Path{ 
    struct Point{ 
     float x; 
     float y; 
     struct EnableAssignment {}; 
    }; 
    Point segment[MAX_SIZE]; 
}; 

La strumentazione viene quindi utilizzato in questo modo:

template<class T, class U = typename T::EnableAssignment> 
Point & operator = (const T & that) 

[Simplified live example]


Il codice utilizza sopra argomento modello predefinito in un modello di funzione, introdotto solo in C++ 11.Prima di allora, si dovrebbe invocare SFINAE in qualche altro modo:

template <class L, class R> 
struct SfinaeThenRight 
{ 
    typedef R type; 
}; 

template <class T> 
typename SfinaeThenRight<typename T::EnableAssignment, Point&>::type operator = (const T & that) 

[Simplified C++98 live example]

+0

Sì, questo è l'approccio migliore. Questo è quello che stavo cercando, ma mi hai battuto su di esso. Basta correggere il codice per essere compilabile. – SergeyA

+0

@SergeyA Cosa c'è di sbagliato in questo? – Angew

+0

Prova a compilarlo. La tua firma per operator = non è corretta. Punto non è un tipo che puoi usare così, è un tipo interno di Path (o lo metti in definizione di Punto). – SergeyA

2
template<size_t OTHER_SIZE> 
Point & operator = (const typename Path<OTHER_SIZE>::Point & that) 

non funziona perché l'argomento modello OTHER_SIZE sul struct esterno non poteva essere dedotta. Si può solo:

template<typename T> 
Point & operator = (const T & that) 
{ 
    x = that.x; 
    y = that.y; 
    return *this; 
} 

Nota che se viene passato qualcosa senza membro x e y si otterrà un errore di compilazione, che dovrebbe essere sufficiente per questo caso.

LIVE

+0

Questa è una soluzione terribile. Mangia volentieri ** qualsiasi cosa ** che abbia x e y in essi, e maschera un potenziale errore logico nel programma. – SergeyA

+0

@SergeyA Dovrebbe essere sufficiente per il caso dell'OP. Se qualcosa di incompatibile è passato come rh avremo un errore del compilatore. Anche la complessità inutile potrebbe far male. – songyuanyao

+0

Il problema non è con qualcosa che non ha x o y su di esso. Il problema è con qualcosa che lo fa, ma non ha alcuna relazione con Pointer. – SergeyA