2015-09-04 6 views
5

Из того, что я понимаю, функция constexpr может быть выполнена во время компиляции, а также во время выполнения, в зависимости от того, может ли вся оценка быть выполнена во время компиляции или нет.Как я могу выполнить команду runtime assert в функции constexpr?

Однако вы не можете перегружать эту функцию, чтобы иметь время выполнения и копию времени компиляции.

Так что мой вопрос в том, как я могу включить в runtime assert, чтобы гарантировать, что выполнение функции выполнения передается действительными параметрами вместе с моим static_assert?

ответ

4

Эрик Niebler охватывает этот вопрос хорошо Assert and Constexpr in C++11, он указывает на то, что использование утверждают в функции constexpr не допускается C++ 11, но это разрешено в C++ 14 (As part of the Relaxing constraints on constexpr functions proposal) и обеспечивает следующий фрагмент:

constexpr bool in_range(int val, int min, int max) 
{ 
    assert(min <= max); // OOPS, not constexpr 
    return min <= val && val <= max; 
} 

Если нам нужно поддерживать C++ 11, то есть несколько альтернатив. Очевидным является использование throw, но это, поскольку он указывает, что это превращает то, что должно быть неустранимой ошибкой в ​​восстанавливаемое, поскольку вы можете поймать исключение.

Он предложить несколько вариантов:

  1. Использование броска с noexcept specifier:

    constexpr bool in_range(int val, int min, int max) noexcept 
    { 
        return (min <= max) 
        ? min <= val && val <= max 
        : throw std::logic_error("Assertion failed!"); 
    } 
    

    если исключение выходит из функции зЬй :: прекратить будет называться.

  2. Вызов std::quick_exit из конструктора типа исключений:

    struct assert_failure 
    { 
        explicit assert_failure(const char *sz) 
        { 
         std::fprintf(stderr, "Assertion failure: %s\n", sz); 
         std::quick_exit(EXIT_FAILURE); 
        } 
    }; 
    
    constexpr bool in_range(int val, int min, int max) 
    { 
        return (min <= max) 
         ? min <= val && val <= max 
         : throw assert_failure("min > max!"); 
    } 
    
  3. Pass лямбда-выражения, утверждающая конструктору типа исключений:

    constexpr bool in_range(int val, int min, int max) 
    { 
        return (min <= max) 
         ? min <= val && val <= max 
         : throw assert_failure(
          []{assert(!"input not in range");} 
         ); 
    } 
    
+0

Я также выяснили, что вы можете использовать assert непосредственно в контексте списка. 'constexpr bool in_range (int val, int min, int max) {return (assert (min <= max), min <= val && val <= max); } 'В принципе, вы должны сделать так, чтобы он никогда не мог получить вызов non-constexpr, если он используется в контексте constexpr при ошибке. Это работает, потому что assert - это макрос к тернарному выражению, которое оценивает вызов базовой функции non-constexpr при ошибке. – Adrian

+0

@Adrian интересно отметить, что [оператор запятой разрешен только в постоянных выражениях в C++ 11] (http://stackoverflow.com/q/27324573/1708801). –

+0

@Adrian, хотя это не будет переносимым, поскольку оно опирается на деталь реализации 'assert', которая не покрывается стандартом. –

1

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

Этот вопрос показывает пример кода, где это происходит: Passing constexpr objects around

также связано: What happens when an exception is thrown while computing a constexpr?

 Смежные вопросы

  • Нет связанных вопросов^_^