2016-01-07 17 views
9

Si noti che questo è non un duplicato delle tante domande su StackOverflow riguardanti gcc, sto usando Visual Studio 2013.costruttore std :: regex genera un'eccezione

Questo semplice costruzione di un'espressione regolare tiri std::regex_error :

bool caseInsensitive = true; 
char pattern[] = "\\bword\\b"; 
std::regex re(pattern, std::regex_constants::ECMAScript | (caseInsensitive ? std::regex_constants::icase : 0)); 

l'errore effettivo restituito dal what sull'oggetto eccezione non è coerente. Di solito è una parestesia o una parentesi non corrispondenti. Perché?

risposta

11

Il problema si presenta a causa dei molteplici costruttori disponibili per std::regex. Tracing nel costruttore l'ho mostrato usando uno che non intendevo!

ho voluto usare questo:

explicit basic_regex(_In_z_ const _Elem *_Ptr, 
    flag_type _Flags = regex_constants::ECMAScript) 

ma ho avuto questa invece:

basic_regex(_In_reads_(_Count) const _Elem *_Ptr, size_t _Count, 
    flag_type _Flags = regex_constants::ECMAScript) 

L'espressione ternaria nelle bandiere fa sì che il tipo di cambiare a int, le partite che non è più flag_type nella firma del costruttore. Dal momento che lo corrisponde a corrisponde a size_t, chiama invece il costruttore. I flag vengono erroneamente interpretati come la dimensione della stringa, con conseguente comportamento non definito quando si accede alla memoria oltre la fine della stringa.

Il problema non è specifico di Visual Studio. Sono stato in grado di duplicarlo in gcc: http://ideone.com/5DjYiz

Può essere risolto in due modi. In primo luogo è un cast esplicito dell'argomento:

std::regex re(pattern, static_cast<std::regex::flag_type>(std::regex_constants::ECMAScript | (caseInsensitive ? std::regex_constants::icase : 0))); 

In secondo luogo è quello di evitare costanti intere nell'espressione ternario:

std::regex re(pattern, caseInsensitive ? std::regex_constants::ECMAScript | std::regex_constants::icase : std::regex_constants::ECMAScript); 
6

non trovo nessuna delle soluzioni proposte particolarmente interessanti o esteticamente gradevoli. Penso che io preferirei qualcosa di simile:

auto options = std::regex_constants::ECMAScript; 
if (caseInsensitive) 
    options |= std::regex_constants::icase; 

std::regex re(pattern, options); 

Se, per qualche ragione sbagliata, davvero insistere su una sola riga di codice, mi piacerebbe utilizzare un oggetto di valore costruito del tipo corretto nel ternario espressione:

std::regex re(pattern, std::regex_constants::ECMAScript | (caseInsensitive ? std::regex_constants::icase : std::regex_constants::std::regex_option_type{})); 

Oppure, dal momento che ECMAScript è l'impostazione predefinita, si utilizza:

std::regex re(pattern, (caseInsensitive ? std::regex_constants::icase : std::regex_constants::ECMAScript)); 

almeno ai miei occhi, il primo di questi è chiaramente preferibile però.

+0

La tua soluzione è sicuramente più leggibile, grazie. –

Problemi correlati