2015-09-04 13 views
5

Từ những gì tôi hiểu, một hàm constexpr có thể được thực hiện tại thời gian biên dịch cũng như thời gian chạy, tùy thuộc vào việc toàn bộ việc đánh giá có thể được thực hiện tại thời gian biên dịch hay không.Làm thế nào tôi có thể thực hiện một thời gian chạy khẳng định trong một hàm constexpr?

Tuy nhiên, bạn không thể quá tải hàm này để có thời gian chạy và đối tác thời gian biên dịch. Vì vậy, câu hỏi của tôi là, làm thế nào tôi có thể đặt trong một thời gian chạy khẳng định để đảm bảo rằng việc thực hiện các chức năng thời gian chạy được thông qua các thông số hợp lệ cùng với static_assert của tôi? Không.

Trả lời

4

Eric Niebler bao gồm vấn đề này tốt trong Assert and Constexpr in C++11, ông chỉ ra rằng việc sử dụng khẳng định trong một chức năng constexpr không được phép trong C++ 11 nhưng nó được cho phép trong C++ 14 (As part of the Relaxing constraints on constexpr functions proposal) và cung cấp đoạn mã sau:

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

Nếu chúng ta phải hỗ trợ C++ 11 thì có một số lựa chọn thay thế. Một trong những rõ ràng là sử dụng ném nhưng điều này như ông chỉ ra điều này biến những gì nên là một lỗi không thể phục hồi vào một phục hồi kể từ khi bạn có thể bắt ngoại lệ.

Ông đề xuất một số giải pháp thay thế:

  1. Sử dụng ném với 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!"); 
    } 
    

    nếu một ngoại lệ rời khỏi chức năng std :: chấm dứt sẽ được gọi.

  2. Gọi std::quick_exit từ các nhà xây dựng của một loại ngoại lệ:

    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. Vượt qua một biểu thức lambda mà khẳng định để các nhà xây dựng của một loại ngoại lệ:

    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

Tôi cũng đã phát hiện ra rằng bạn có thể sử dụng khẳng định trực tiếp trong ngữ cảnh danh sách. 'constexpr bool in_range (int val, int min, int max) {return (khẳng định (min <= max), min <= val && val <= max); } 'Về cơ bản, bạn phải làm cho nó để nó không bao giờ có thể nhận được cuộc gọi không constexpr nếu được sử dụng trong một bối cảnh constexpr về thất bại. Điều này có tác dụng bởi vì, khẳng định là một macro với một biểu thức bậc ba, nó đánh giá để gọi hàm không phải là constexpr cơ bản về lỗi. – Adrian

+0

@Adrian thú vị cần lưu ý rằng [toán tử dấu phẩy chỉ được phép trong các biểu thức liên tục trong C++ 11] (http://stackoverflow.com/q/27324573/1708801). –

+0

@Adrian mặc dù điều đó sẽ không thể di chuyển vì nó dựa trên chi tiết triển khai của 'khẳng định' không được bao gồm trong tiêu chuẩn. –

1

Bạn có thể ném ngoại lệ. Nếu một ngoại lệ được ném vào thời gian biên dịch từ một hàm constexpr, nó về cơ bản được tính là không thực hiện một khẳng định tĩnh. Nếu nó xảy ra trong thời gian chạy, nó sẽ chỉ là một ngoại lệ như bình thường.

Câu hỏi này cho thấy một ví dụ mã nơi này xảy ra: Passing constexpr objects around

Cũng liên quan: What happens when an exception is thrown while computing a constexpr?

Các vấn đề liên quan