2014-09-27 17 views
8

Tôi có một số hàm constexpr ngắn gọn trong các thư viện của tôi thực hiện một số phép tính đơn giản. Tôi sử dụng cả hai trong bối cảnh thời gian chạy và biên dịch.Cách khác để xác nhận các hàm constexpr

Tôi muốn thực hiện một số xác nhận trong phần thân của các chức năng này, tuy nhiên assert(...) không hợp lệ trong chức năng constexpr và không thể sử dụng static_assert(...) để kiểm tra tham số chức năng.

Ví dụ:

constexpr int getClamped(int mValue, int mMin, int mMax) noexcept 
{ 
    assert(mMin <= mMax); // does not compile! 
    return mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue); 
} 

Có cách nào để séc xem chức năng đang được thực hiện trong một thời gian chạy hoặc thời gian biên dịch liên tục và thực hiện assert chỉ khi nó đang được thực hiện tại thời gian chạy ?

constexpr int getClamped(int mValue, int mMin, int mMax) noexcept 
{ 
    assert_if_runtime(mMin <= mMax); 
    return mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue); 
} 
+1

@dasblinkenlight: Ý của tôi là 'static_assert' [không có ý nghĩa trong dịp này] (http://ideone.com/6yjdAE). –

+0

(Disclaimer: Tôi là một noob và không bao giờ sử dụng một constexpr trong cuộc sống thực.) Dựa trên tìm kiếm Google ban đầu của tôi, trừ khi trình biên dịch của bạn hỗ trợ [N3652] (http://www.open-std.org/jtc1/sc22/ wg21/docs/papers/2013/n3652.html) thư giãn C++ 11 'constexpr', nó không thể làm những gì bạn yêu cầu. Khi điều này có sẵn, bạn sẽ có thể ném một ngoại lệ như 'std :: range_error' thay cho' static_assert'. Bạn có thể thử sử dụng [Clang 3.4 with std = C++ 14] (http://clang.llvm.org/cxx_status.html). – rwong

+0

yêu cầu của bạn không đúng đối với Clang ở chế độ '-std = C++ 1y', khẳng định sẽ hoạt động tốt.bạn nên gắn thẻ lại thành 'C++ 11' nếu bạn bị giới hạn ở tiêu chuẩn đó. – TemplateRex

Trả lời

4

Tôi tin rằng assert sẽ hoạt động cho bạn khi g ++ thực hiện N3652, Relaxing constraints on constexpr functions. Hiện tại, this status page cho biết rằng điều này chưa được triển khai.

assert không hoạt động (trong các hàm constexpr) trên trình biên dịch tiếng kêu hiện tại do Apple cung cấp, với -std=c++1y.

Tại thời điểm này, tôi thấy không có gì trong tiêu chuẩn đảm bảo rằng assert sẽ hoạt động trong các hàm constexpr và đảm bảo đó sẽ là bổ sung chào mừng cho tiêu chuẩn (ít nhất là bởi tôi).

Cập nhật

Richard Smith đã thu hút sự chú ý của tôi để LWG 2234 gửi bởi Daniel Krügler mà đang nỗ lực để tạo ra sự đảm bảo tôi đề cập đến ở trên.

+1

1 Tôi đã được sử dụng khẳng định tất cả trên mã constexpr và tôi rất hài lòng với nó – TemplateRex

+0

không, nó sẽ không làm việc, bởi vì 'assert' vĩ mô cuối cùng phải gọi' abort' (thường là thông qua chức năng trung gian như __assert_fail), mà không phải là một chức năng constexpr. – o11c

+0

@ o11c Nếu 'khẳng định' luôn được gọi là 'hủy bỏ', nó sẽ bị hỏng. – Potatoswatter

8

Ném một ngoại lệ có thể hữu ích khi trình biên dịch bỏ qua phần thời gian chạy khi nó không được ném.

#include <cassert> 

constexpr int getClamped(int mValue, int mMin, int mMax) 
{ 
    return (mMin <= mMax) ? 
      (mValue < mMin ? mMin : (mValue > mMax ? mMax : mValue)) : 
      throw "mMin must be less than or equal to mMax"; 
} 

int main(int argc, char** argv) 
{ 
    // These two work: 
    static_assert(getClamped(42, 0, 100) == 42, "CT"); 
    assert(getClamped(argc, 0, 100) == argc); 

    // Fails at compile-time: 
    // static_assert(getClamped(42, 100, 0) == 42, "CT"); 

    // Fails at run-time: 
    // assert(getClamped(argc, 100, 0) == argc); 
} 

Live example

+0

Sau khi một số người chơi xung quanh (cố gắng tìm cách để làm quá tải về công việc 'constexpr'), tôi nghĩ đây là cách tốt nhất/duy nhất để làm điều đó. Nhưng ý nghĩ ném từ một chức năng kẹp làm tôi kinh ngạc ... –

5

Một sự tinh tế về câu trả lời Daniel Frey là sử dụng noexcept trên constexpr chức năng để biến các lỗi thời gian chạy vào một cuộc gọi đến std::terminate. Lỗi xác nhận không thể khôi phục được; họ nên tạm dừng quá trình ngay lập tức. Biến chúng thành ngoại lệ là một ý tưởng rất tồi tệ.

#include <exception> 
#include <stdexcept> 

struct assert_failure 
    : std::logic_error 
{ 
    explicit assert_failure(const char *sz) 
     : std::logic_error(sz) 
    {} 
}; 

constexpr bool in_range(int i, int j, int k) noexcept 
{ 
    return (i <= j && j <= k) ? true : throw assert_failure("input not in range"); 
} 

int main(int argc, char* argv[]) 
{ 
    constexpr bool b1 = in_range(0, 4, 5); // OK! 
    constexpr bool b2 = in_range(0, 6, 5); // Compile-time error! 
    bool b3 = in_range(0, 4, argc);  // May or may not terminate the process 
} 

Các lỗi runtime cho tôi trông giống như:

terminate called after throwing an instance of 'assert_failure' 
    what(): input not in range 
Aborted (core dumped) 

Hy vọng rằng sẽ giúp.

+0

+1 Tôi đã loại bỏ một cách rõ ràng 'noexcept', nhưng nó có những công dụng của nó nên cảm ơn vì đã chỉ ra điều đó. Tất nhiên, đó là một quyết định bạn cần phải thực hiện, bình thường trong công việc môi trường của tôi, chấm dứt quá trình này là một cái gì đó chúng tôi cố gắng tránh nhưng tôi có rất nhiều thiện cảm cho thất bại sớm, không khó :) –

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