2012-02-29 12 views
5

Stavo solo cercando di modificare un letterale binario operator ""_b, ma mi sono bloccato cercando di terminare la ricorsione. Come definire una funzione che può essere chiamata utilizzando un elenco di parametri del template esplicito vuoto, che non è in conflitto con un sovraccarico del pacchetto di parametri? Quindi, ispirazione: abbina l'espansione del pacchetto vuoto a qualcosa di stravagante.Un'espansione del value pack vuoto corrisponde a un pacchetto di tipo o un parametro di tipo facoltativo?

Ma GCC lamenta che i tipi inesistenti dell'elenco di argomenti vuoti non concordano con i tipi non richiesti esplicitamente dell'elenco di parametri. Dovrebbe funzionare in questo modo?

template< char head, char ... tail > 
constexpr unsigned long long parse_binary() { 
    return ((head - '0') << sizeof ... (tail)) 
     + parse_binary< tail ... >(); // Error: no overload for termination. 
} 

template< typename = void > // I want this to match an empty pack of chars. 
// template< short = 0 > // even this would do. 
constexpr unsigned long long parse_binary() { 
    return 0; 
} 

template< char ... digits > 
constexpr unsigned long long operator ""_b() { 
    return parse_binary< digits ... >(); 
} 

#include <iostream> 

int main() { 
    std::cout << 010101_b << '\n'; 
} 

Nota: la domanda non sta applicando operator ""_b. Questo problema può essere risolto espandendo il pacchetto nell'elenco dei parametri e passando i tipi std::integral_constant in giro.

Nota 2: questo codice funziona effettivamente con una regolazione minore; vedi la mia risposta qui sotto. Ma questo non affronta direttamente la domanda. Hmm, forse avrei dovuto modificare questo invece di rispondere ...

+0

In generale si può terminare la ricorsione, rendendo il modello originale 'template ', e usa 'template ' per la terminazione - ma immagino che non sia quello che stai chiedendo. –

+1

@ BjörnPollex No, quindi passare due argomenti sarebbe ambiguo. I pacchetti possono essere vuoti. Un 'template < char head >' e un 'template ' farebbero il trucco, ma sì, non è questa la domanda. – Potatoswatter

risposta

0

Nessuna parola ufficiale sulla conformità di tale ingannevole matching, ma il codice fornito da funziona se i due overload sono stati trasposti.

Il secondo sovraccarico di terminazione non è visibile al primo perché il primo risolve il nome al momento della definizione del modello. Solo le chiamate di funzione che dipendono da un parametro di modello hanno una ricerca differita fino al momento dell'istanziazione.

Giusto per essere chiari, questo funziona :

template< typename = void > // Define this one first! 
constexpr unsigned long long parse_binary() { 
    return 0; 
} 

template< char head, char ... tail > 
constexpr unsigned long long parse_binary() { 
    return ((head - '0') << sizeof ... (tail)) 
     + parse_binary< tail ... >(); // Bingo: overload found. 
} 
+0

iirc in C++ 11 abbiamo un pallino esplicito che dipende dal nome di una funzione se è un id modello e uno degli argomenti del modello dipende. ora per sapere che si tratta di un id di modello, il compilatore deve prima cercarlo su un modello, ma che io zhink non preclude una seconda ricerca del tempo di istanziazione. –

+0

sì ho verificato che si tratta di un bug GCC: "parse_binary < tail ... >()" dovrebbe fare anche la ricerca dipendente da istanze di "parse_binary". –

+0

@ JohannesSchaub-litb: interessante! Hai archiviato l'errore? – Potatoswatter

4

Non sarebbe meglio terminare la ricorsione di un personaggio?

template<char Ch> 
constexpr unsigned long long parse_binary(){ 
    return Ch - '0'; 
}; 

// second head to disambiguate 
template< char head1, char head2, char ... tail > 
constexpr unsigned long long parse_binary() { 
    return ((head1 - '0') << sizeof ... (tail)+1) + parse_binary< head2, tail ... >(); 
} 

In ogni caso, il problema è che parse_binary per lo zero caratteri deve essere dichiarato prima che la versione variadic, come Clang fa bene fuori:

error: call to function 'parse_binary' that is neither visible in 
     the template definition nor found by argument-dependent lookup 

// call trace... 

note: 'parse_binary' should be declared prior to the call site 
     constexpr unsigned long long parse_binary() { 
+0

LOL. Ho appena scritto la mia risposta a Björn prima di scorrere fino a questo. Come ho detto nella nota, questa è una domanda sui pacchetti di parametri, non sull'implementazione di valori letterali binari. L'elegante soluzione è espandere il pacchetto nella lista dei parametri di funzione. – Potatoswatter

+0

Ah, sì, non è consentito espandere il set di overload candidate, a meno che il nome sovraccarico non sia dipendente da ADL su un parametro del modello. Aha, combinato con il commento di Luc in chat, penso di capire adesso. – Potatoswatter

Problemi correlati