2014-12-04 2 views
4

Я решил дать тогда новое C++14 определение constexpr a spin и, чтобы получить максимальную отдачу от него, я решил написать небольшой синтаксический анализатор строк компиляции. Тем не менее, я борюсь с тем, чтобы сохранить объект 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); 
} 

I использует str_const class представленный Scott Schurr at 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 -ness. Это привело меня к следующим вопросам:

  1. Является ли моя интерпретация правильной?
  2. Почему это поведение соответствует стандарту?

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

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

* Вы видите другой подход к решению проблемы? * 'Constexpr auto nOpen = numOpen (str);' экземпляр не должен быть 'constexpr' для оценки функции во время компиляции –

ответ

6

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

const auto nOpen = numOpen(str); 

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

+0

Я предполагаю, что это означает, что невозможно создать объект 'constexpr' внутри функции из строкового литерала, переданного этой функции? Какой позор, так как я хотел обернуть функцию 'check' внутри моего фактического парсера. Что-то вроде [этого] (http://pastebin.com/CuG37r45) (некомпилирующего) макета кода. – elemakil