Il costruttore di std :: vector range può invocare conversioni esplicite?


14

Il seguente programma è ben formato?

#include <vector>
struct A {
    explicit A(int) {}
};
int main() {
    std::vector<int> vi = {1, 2, 3, 4, 5};
    std::vector<A> va(vi.begin(), vi.end());
}

Secondo C ++ 17 [sequence.reqmts], il requisito per

X u(i, j);

dove si Xtrova un contenitore sequenza, è:

Tdeve essere EmplaceConstructiblein Xda *i.

Tuttavia, nel paragrafo precedente si afferma che:

ie jdenota iteratori che soddisfano i requisiti di iteratore di input e fanno riferimento a elementi implicitamente convertibili in value_type,

Quindi mi sembra che entrambi i requisiti debbano essere soddisfatti: il tipo di valore dell'intervallo deve essere implicitamente convertibile nel tipo di valore del contenitore e EmplaceConstructible deve essere soddisfatto (il che significa che l'allocatore deve essere in grado di eseguire l'inizializzazione richiesta) . Poiché intnon è implicitamente convertibile in A, questo programma dovrebbe essere mal formato.

Tuttavia, sorprendentemente, sembra compilarsi sotto GCC .


(Per la cronaca, non è solo gcc: godbolt.org/z/ULeRDw )
Max Langhof

In questo caso non è richiesta alcuna conversione implicita, poiché il costruttore esplicito si adatta già al tipo. Penso che la descrizione sia confusa, ma la costruzione esplicita è sempre meglio della conversione implicita prima della costruzione.
JHBonarius

Risposte:


2

È solo un requisito per i container di sequenza supportare la costruzione da iteratori che soddisfano i criteri di convertibilità implicita.

Questo da solo non impedisce ai contenitori di sequenze di supportare quella costruzione da iteratori che non soddisfano tali criteri per quanto ne so 1 . C'è una regola esplicita al riguardo:

Se il costruttore ... viene chiamato con un tipo InputIterator che non si qualifica come iteratore di input , il costruttore non deve partecipare alla risoluzione del sovraccarico.

Non è chiaro cosa significhi "qualificarsi come iteratore di input" esattamente nel contesto. È un modo informale per esprimere Cpp17InputIterator o tenta di fare riferimento ai requisiti di iej? Non lo so. Indipendentemente dal fatto che sia consentito o meno, lo standard non ha un requisito rigoroso per rilevarlo:

[Container.requirements.general]

Il comportamento di alcune funzioni dei membri del contenitore e delle guide alla detrazione dipende dal fatto che i tipi si qualifichino come iteratori di input o allocatori. La misura in cui un'implementazione determina che un tipo non può essere un iteratore di input non è specificata, tranne per il fatto che come tipi integrali minimi non possono essere qualificati come iteratori di input. ...

Con l'interpretazione che qualsiasi Cpp17InputIterator "si qualifica come iteratore di input", il programma di esempio non dovrebbe essere mal formato. Ma non è nemmeno garantito che sia ben formato.

1 In tal caso, potrebbe essere considerato un problema di qualità dell'attuazione da avvertire quando si fa affidamento su di esso. D'altra parte, questa limitazione alle conversioni implicite può essere considerata un difetto .


PS Questo viene compilato senza avvisi in Clang (con libc ++) e anche in Msvc.

PPS Questa formulazione sembra essere stata aggiunta in C ++ 11 (che è naturale, così come sono stati introdotti anche costruttori espliciti).


1
Dipende molto dal significato di "non si qualifica come iteratore di input" . A differenza di quanto sopra , in realtà non dice Cpp17InputIterator, quindi non mi è chiaro se "e fare riferimento a elementi implicitamente convertibili in value_type" sia incluso in "input iterator". In tal caso, il costruttore non dovrebbe partecipare alla risoluzione del sovraccarico e il programma dovrebbe essere mal formato.
Max Langhof,

1
Quindi, ogni classe di libreria standard può avere costruttori extra senza emettere una diagnostica quando vengono usati quei costruttori extra? Mi sembra intuitivamente sbagliato ...
Brian,

@Brian non sono sicuro se i suoi "costruttori extra", ma forse "implementazioni più specifiche di costruttori che consentono più spazio". Controllare ogni input potrebbe avere un impatto significativo sulle prestazioni, quindi non so se sarebbe la strada da percorrere ...
JHBonarius

@Brian Sarebbe certamente una cattiva idea anche se non esplicitamente vietata. In questo caso stiamo solo valutando se un costruttore richiesto è autorizzato a supportare tipi di iteratori che non è necessario supportare. In questo caso esiste un esplicito requisito di "non partecipazione", come sottolineato da Max, che certamente non lo consentirebbe. Ma non è chiaro cosa significhi "qualificarsi come input iteratore" esattamente nel contesto. È un modo informale di esprimere Cpp17InputIteratoro tenta di fare riferimento ai requisiti di ie j? Non lo so.
Eerorika,

2
1) In C ++ impostiamo lo standard basso. . 2) I costruttori sono funzioni membro non virtuali . 3) Vedi LWG 3297 ; tuttavia non sono particolarmente convinto che dovremmo rimuovere il requisito di conversione implicita.
TC
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.