I decided to give then new C++14
definition of constexpr
a spin and to get the most out of it I decided to write a little compile-time string parser. However, I'm struggling with keeping my object a constexpr
while passing it to a function. Consider the following code:
#include <cstddef>
#include <stdexcept>
class str_const {
const char * const p_;
const std::size_t sz_;
public:
template <std::size_t N>
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 );
}
I uses the str_const
class presented by Scott Schurr at C++Now 2012 in a version modified for C++14
.
The above code will fail to compile with the error (clang-3.5
)
error: constexpr variable 'nOpen' must be initialized by a constant expression
constexpr auto nOpen = numOpen( str );
~~~~~~~~~^~~~~
Which leads me to the conclusion that you can not pass around a constexpr
object without losing its constexpr
-ness. This lead me to the following questions:
- Is my interpretation correct?
Why is this the behaviour the standard dictates?
I don't see the problem in passing a
constexpr
object around. Sure, I could rewrite my code to fit into a single function, but that leads to cramped code. I would assume that factoring separate functionality into separate units of code (functions) should be good style for compile time operations too.- As I said before the compiler error can be solved by moving the code from the bodies of separate testing functions (such as
numOpen
) into the body of the top-level functioncheck
. However, I don't like this solution since it creates one huge and cramped function. Do you see a different approach to solving the problem?