Передача объектов constexpr вокруг

Затем я решил опробовать новое C++14 определение constexpr и, чтобы получить от него максимальную отдачу, я решил написать небольшой анализатор строк во время компиляции. Однако я изо всех сил пытаюсь сохранить свой объект constexpr при передаче его функции. Рассмотрим следующий код:

#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 );
}

Я использую класс str_const, представленный Скотт Шурр на C++Now 2012 в версии, модифицированной для C++14 .

Приведенный выше код не скомпилируется с ошибкой (clang-3.5)

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

Это приводит меня к выводу, что вы не можете обойти объект constexpr, не потеряв при этом его constexpr-ности. Это привело меня к следующим вопросам:

  1. Верна ли моя интерпретация?

  2. Почему это поведение диктует стандарт?

    Я не вижу проблемы в передаче объекта constexpr. Конечно, я мог бы переписать свой код, чтобы он вписался в одну функцию, но это приводит к тесноте кода. Я бы предположил, что разложение отдельных функций на отдельные блоки кода (функции) также должно быть хорошим стилем для операций времени компиляции.

  3. Как я уже говорил, ошибку компилятора можно устранить, переместив код из тела отдельных функций тестирования (таких как numOpen) в тело функции верхнего уровня check. Однако мне не нравится это решение, так как оно создает одну огромную и тесную функцию. Видите ли вы другой подход к решению проблемы?


person elemakil    schedule 04.12.2014    source источник
comment
Вы видите другой подход к решению проблемы? constexpr auto nOpen = numOpen( str ); instance не обязательно должен быть constexpr для оценки функции во время компиляции.   -  person Piotr Skotnicki    schedule 04.12.2014


Ответы (1)


Причина в том, что внутри функции constexpr параметры не являются константными выражениями, независимо от того, являются ли аргументы таковыми. Вы можете вызывать constexpr функции внутри других, но параметры constexpr функции не находятся constexpr внутри, что делает любой вызов функции (даже constexpr функций) не константным выражением - внутри.

const auto nOpen = numOpen( str );

Достаточно. Только когда вы просматриваете вызов снаружи, проверяется constexpr-ность выражений внутри, определяя, является ли весь вызов constexpr или нет.

person Columbo    schedule 04.12.2014
comment
Я предполагаю, что это означает, что невозможно создать объект constexpr внутри функции из строкового литерала, переданного этой функции? Это позор, так как я хотел обернуть функцию check внутри моего настоящего парсера. Что-то вроде этого (не компилируемого) макета кода. - person elemakil; 04.12.2014