4

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:

  1. Is my interpretation correct?

  2. 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.

  3. 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 function check. 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?

1
  • 2
    Do you see a different approach to solving the problem? constexpr auto nOpen = numOpen( str ); instance doesn't need to be constexpr to evaluate the function at compile time Commented Dec 4, 2014 at 10:48

1 Answer 1

7

The reason is that inside a constexpr function, parameters aren't constant expressions, regardless of whether the arguments are. You can call constexpr functions inside others, but the parameters of a constexpr function aren't constexpr inside, making any function call (even to constexpr functions) not a constant expression - inside.

const auto nOpen = numOpen( str );

Suffices. Only once you view the call from outside the constexpr-ness of the expressions inside is verified, deciding whether the whole call is constexpr or not.

Sign up to request clarification or add additional context in comments.

1 Comment

I guess this means that it is not possible to create a constexpr object inside a function from a string literal passed to that function? Which is a shame since I wanted to wrap the check function inside my actual parser. Something like this (non-compiling) mock-up code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.