Queste informazioni sono datate. Deve essere aggiornato secondo l'ultima bozza di Concepts Lite.
La sezione 3 della proposta sui vincoli copre questo aspetto in modo ragionevole.
La proposta di concetti è stata messa in secondo piano per un breve periodo nella speranza che i vincoli (cioè i concetti-lite) possano essere sviluppati e implementati in una scala temporale più breve, attualmente mirando a qualcosa in C ++ 14. La proposta sui vincoli è concepita per agire come una transizione graduale a una definizione successiva dei concetti. I vincoli fanno parte della proposta di concetti e sono un elemento costitutivo necessario nella sua definizione.
Nella progettazione di librerie di concetti per C ++ , Sutton e Stroustrup considerano la seguente relazione:
Concetti = Vincoli + Assiomi
Per riassumere rapidamente il loro significato:
- Vincolo: predicato su proprietà valutabili staticamente di un tipo. Requisiti puramente sintattici. Non un'astrazione di dominio.
- Assiomi: requisiti semantici dei tipi che si presume siano veri. Non controllato staticamente.
- Concetti - Requisiti generali e astratti degli algoritmi sui loro argomenti. Definito in termini di vincoli e assiomi.
Quindi, se aggiungi assiomi (proprietà semantiche) ai vincoli (proprietà sintattiche), ottieni concetti.
Concetti-Lite
La proposta di concetti-lite ci porta solo la prima parte, i vincoli, ma questo è un passo importante e necessario verso concetti a tutti gli effetti.
Vincoli
I vincoli riguardano la sintassi . Ci danno un modo per distinguere staticamente le proprietà di un tipo in fase di compilazione, in modo da poter limitare i tipi usati come argomenti del modello in base alle loro proprietà sintattiche. Nell'attuale proposta di vincoli, sono espressi con un sottoinsieme di calcolo proposizionale utilizzando connettivi logici come &&
e ||
.
Diamo un'occhiata a un vincolo in azione:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
Qui stiamo definendo un modello di funzione chiamato sort
. La nuova aggiunta è la clausola require . La clausola require fornisce alcuni vincoli sugli argomenti del modello per questa funzione. In particolare, questo vincolo dice che il tipo Cont
deve essere un Sortable
tipo. Una cosa interessante è che può essere scritto in una forma più concisa come:
template <Sortable Cont>
void sort(Cont& container);
Ora se provi a passare qualcosa che non è considerato Sortable
a questa funzione, otterrai un simpatico errore che ti dice immediatamente che il tipo dedotto per T
non è un Sortable
tipo. Se lo avessi fatto in C ++ 11, avresti avuto un orribile errore generato dall'interno della sort
funzione che non ha senso per nessuno.
I predicati dei vincoli sono molto simili ai tratti di tipo. Prendono un tipo di argomento modello e ti danno alcune informazioni al riguardo. I vincoli tentano di rispondere ai seguenti tipi di domande sul tipo:
- Questo tipo ha l'operatore tale e quello sovraccarico?
- Questi tipi possono essere usati come operandi per questo operatore?
- Questo tipo ha tratti del genere?
- Questa espressione costante è uguale a quella? (per argomenti di modello non di tipo)
- Questo tipo ha una funzione chiamata yada-yada che restituisce quel tipo?
- Questo tipo soddisfa tutti i requisiti sintattici per essere utilizzato come quello?
Tuttavia, i vincoli non intendono sostituire i tratti del tipo. Invece, lavoreranno mano nella mano. Alcuni tratti di tipo possono ora essere definiti in termini di concetti e alcuni concetti in termini di tratti di tipo.
Esempi
Quindi la cosa importante dei vincoli è che non si preoccupano della semantica di una virgola. Alcuni buoni esempi di vincoli sono:
Equality_comparable<T>
: Controlla se il tipo ha ==
entrambi gli operandi dello stesso tipo.
Equality_comparable<T,U>
: Verifica se è presente un ==
con operandi sinistro e destro dei tipi specificati
Arithmetic<T>
: Controlla se il tipo è un tipo aritmetico.
Floating_point<T>
: Controlla se il tipo è un tipo a virgola mobile.
Input_iterator<T>
: Controlla se il tipo supporta le operazioni sintattiche che un iteratore di input deve supportare.
Same<T,U>
: Controlla se il tipo specificato è lo stesso.
Puoi provare tutto questo con una build speciale di GCC .
Oltre i concetti-Lite
Ora entriamo in tutto oltre la proposta di concetti-lite. Questo è ancora più futuristico del futuro stesso. Tutto da qui in avanti probabilmente cambierà un po '.
Assiomi
Gli assiomi riguardano la semantica . Specificano relazioni, invarianti, garanzie di complessità e altre cose simili. Diamo un'occhiata a un esempio.
Mentre il Equality_comparable<T,U>
vincolo ti dirà che esiste un operator==
che accetta tipi T
e U
, non ti dice cosa significa quell'operazione . Per questo, avremo l'assioma Equivalence_relation
. Questo assioma dice che quando gli oggetti di questi due tipi vengono confrontati con il operator==
dare true
, questi oggetti sono equivalenti. Potrebbe sembrare ridondante, ma certamente non lo è. Si potrebbe facilmente definire un file operator==
che invece si comporta come un file operator<
. Saresti cattivo se lo facessi, ma potresti.
Un altro esempio è un Greater
assioma. Va bene dire che due oggetti di tipo T
possono essere confrontati con operatori >
e <
, ma cosa significano ? L' Greater
assioma dice che se f x
è maggiore di allora y
, allora y
è minore di x
. La specifica proposta un tale assioma assomiglia a:
template<typename T>
axiom Greater(T x, T y) {
(x>y) == (y<x);
}
Quindi gli assiomi rispondono ai seguenti tipi di domande:
- Questi due operatori hanno questa relazione tra loro?
- Questo operatore per questo tipo significa questo?
- Questa operazione su quel tipo ha questa complessità?
- Questo risultato di quell'operatore implica che questo sia vero?
Cioè, si occupano interamente della semantica dei tipi e delle operazioni su quei tipi. Queste cose non possono essere controllate staticamente. Se questo deve essere verificato, un tipo deve in qualche modo dichiarare di aderire a queste semantiche.
Esempi
Ecco alcuni esempi comuni di assiomi:
Equivalence_relation
: Se due oggetti si confrontano ==
, sono equivalenti.
Greater
: Ogni volta x > y
, quindi y < x
.
Less_equal
: Ogni volta x <= y
, quindi !(y < x)
.
Copy_equality
: For x
e y
of type T
: if x == y
, un nuovo oggetto dello stesso tipo creato dalla costruzione della copia T{x} == y
e fermo x == y
(cioè non distruttivo).
Concetti
Ora i concetti sono molto facili da definire; sono semplicemente la combinazione di vincoli e assiomi . Forniscono un requisito astratto sulla sintassi e sulla semantica di un tipo.
Ad esempio, considera il seguente Ordered
concetto:
concept Ordered<Regular T> {
requires constraint Less<T>;
requires axiom Strict_total_order<less<T>, T>;
requires axiom Greater<T>;
requires axiom Less_equal<T>;
requires axiom Greater_equal<T>;
}
Si noti innanzitutto che, affinché il tipo di modello T
sia Ordered
, deve anche soddisfare i requisiti del Regular
concetto. Il Regular
concetto è un requisito di base che il tipo sia ben educato: può essere costruito, distrutto, copiato e confrontato.
Oltre a questi requisiti, i Ordered
requisiti T
soddisfano un vincolo e quattro assiomi:
- Vincolo: un
Ordered
tipo deve avere un'estensione operator<
. Questo è staticamente controllato, quindi deve esistere.
- Assiomi: per
x
e y
di tipo T
:
x < y
dà un rigoroso ordine totale.
- Quando
x
è maggiore di y
, y
è minore di x
e viceversa.
- Quando
x
è minore o uguale a y
, y
non è minore di x
e viceversa.
- Quando
x
è maggiore o uguale a y
, y
non è maggiore di x
e viceversa.
La combinazione di vincoli e assiomi come questo ti dà concetti. Definiscono i requisiti sintattici e semantici per i tipi astratti da utilizzare con gli algoritmi. Gli algoritmi attualmente devono presumere che i tipi utilizzati supporteranno determinate operazioni ed esprimeranno determinate semantiche. Con i concetti, saremo in grado di garantire che i requisiti siano soddisfatti.
Nella progettazione dei concetti più recenti , il compilatore controllerà solo che i requisiti sintattici di un concetto siano soddisfatti dall'argomento modello. Gli assiomi vengono lasciati deselezionati. Poiché gli assiomi denotano semantiche che non sono valutabili staticamente (o spesso impossibili da controllare completamente), l'autore di un tipo dovrebbe dichiarare esplicitamente che il loro tipo soddisfa tutti i requisiti di un concetto. Questo era noto come mappatura concettuale nei progetti precedenti, ma da allora è stato rimosso.
Esempi
Ecco alcuni esempi di concetti:
Regular
i tipi sono costruibili, distruttibili, copiabili e possono essere confrontati.
Ordered
supportano i tipi operator<
e hanno un rigoroso ordinamento totale e altra semantica di ordinamento.
Copyable
i tipi sono copia costruibile, distruttibile e se x
è uguale a y
ed x
è copiato, anche la copia sarà uguale a y
.
Iterator
tipi della devono essere associati value_type
, reference
, difference_type
, e iterator_category
che si devono soddisfare alcuni concetti. Devono inoltre supportare operator++
ed essere dereferenziabili.
La strada verso i concetti
I vincoli sono il primo passo verso una funzionalità completa dei concetti di C ++. Sono un passaggio molto importante, perché forniscono i requisiti staticamente applicabili dei tipi in modo che possiamo scrivere funzioni e classi modello molto più pulite. Ora possiamo evitare alcune delle difficoltà e della bruttezza di std::enable_if
e dei suoi amici della metaprogrammazione.
Tuttavia, ci sono una serie di cose che la proposta sui vincoli non fa:
Non fornisce un linguaggio di definizione dei concetti.
I vincoli non sono mappe concettuali. L'utente non ha bisogno di annotare specificamente i loro tipi in quanto soddisfano determinati vincoli. Vengono controllate staticamente le semplici funzionalità del linguaggio in fase di compilazione.
Le implementazioni dei modelli non sono vincolate dai vincoli sui relativi argomenti del modello. Cioè, se il tuo modello di funzione fa qualcosa con un oggetto di tipo vincolato che non dovrebbe fare, il compilatore non ha modo di diagnosticare ciò. Una proposta di concetti completa sarebbe in grado di farlo.
La proposta di vincoli è stata progettata specificamente in modo che una proposta completa di concetti possa essere introdotta sopra di essa. Con un po 'di fortuna, quella transizione dovrebbe essere una corsa abbastanza fluida. Il gruppo di concetti sta cercando di introdurre vincoli per C ++ 14 (o in un rapporto tecnico subito dopo), mentre i concetti completi potrebbero iniziare ad emergere intorno a C ++ 17.