Passando oggetti constexpr in giro

Ho deciso di dare una nuova definizione di C++14 di constexpr uno spin e per ottenere il massimo da esso ho deciso di scrivere un parser di stringa in fase di compilazione. Tuttavia, sto lottando per mantenere il mio object un constexpr mentre lo passo a una funzione. Considera il seguente codice:

 #include  #include  class str_const { const char * const p_; const std::size_t sz_; public: template  constexpr str_const( const char( & a )[ N ] ) : p_( a ), sz_( N - 1 ) {} constexpr char operator[]( std::size_t n ) const { return n < sz_ ? p_[ n ] : throw std::out_of_range( "" ); } constexpr std::size_t size() const { return sz_; } }; constexpr long int numOpen( const str_const & str ){ long int numOpen{ 0 }; std::size_t idx{ 0 }; while ( idx < str.size() ){ if ( str[ idx ] == '{' ){ ++numOpen; } else if ( str[ idx ] == '}' ){ --numOpen; } ++idx; } return numOpen; } constexpr bool check( const str_const & str ){ constexpr auto nOpen = numOpen( str ); // ... // Apply More Test functions here, // each returning a variable encoding the correctness of the input // ... return ( nOpen == 0 /* && ... Test the variables ... */ ); } int main() { constexpr str_const s1{ "{ Foo : Bar } { Quooz : Baz }" }; constexpr auto pass = check( s1 ); } 

Io uso la class str_const presentata da Scott Schurr al C ++ Now 2012 in una versione modificata per C++14 .

Il codice sopra non riuscirà a compilare con l’errore ( clang-3.5 )

 error: constexpr variable 'nOpen' must be initialized by a constant expression constexpr auto nOpen = numOpen( str ); ~~~~~~~~~^~~~~ 

Il che mi porta alla conclusione che non è ansible aggirare un object constexpr senza perdere il suo constexpr responsabilità. Questo mi ha portato alle seguenti domande:

  1. La mia interpretazione è corretta?
  2. Perché questo è il comportamento dettato dallo standard?

    Non vedo il problema nel passare un object constexpr giro. Certo, potrei riscrivere il mio codice per adattarlo a una singola funzione, ma questo porta a un codice ristretto. Assumerei che il factoring di funzionalità separate in unità separate di codice (funzioni) dovrebbe essere un buon stile anche per le operazioni di compilazione.

  3. Come ho detto prima, l’errore del compilatore può essere risolto spostando il codice dai corpi di funzioni di test separate (come numOpen ) nel corpo del check funzione di primo livello . Tuttavia, non mi piace questa soluzione poiché crea una funzione enorme e angusta. Vedi un approccio diverso alla risoluzione del problema?

Il motivo è che all’interno di una funzione constexpr , i parametri non sono espressioni costanti , indipendentemente dal fatto che gli argomenti siano. Puoi chiamare constexpr funzioni di constexpr all’interno degli altri, ma i parametri di una funzione di constexpr non sono all’interno di constexpr , rendendo qualsiasi chiamata di funzione (anche a funzioni di constexpr ) non un’espressione costante – all’interno .

 const auto nOpen = numOpen( str ); 

È sufficiente Solo una volta che si visualizza la chiamata dall’esterno del constexpr -ness delle espressioni interne viene verificato, decidendo se l’intera chiamata è constexpr oppure no.