2012-11-20 29 views
12

Có cách nào để in giá trị của một giá trị constexpr hoặc #define d tại thời gian biên dịch không? Tôi muốn tương đương với std::cout <<, hoặc một số cách để làm điều gì đó nhưstd :: cout tương đương tại thời gian biên dịch, hoặc static_assert xâu chuỗi các giá trị hằng số biên dịch trong C++ 11

constexpr int PI_INT = 4; 
static_assert(PI_INT == 3, 
       const_str_join("PI_INT must be 3, not ", const_int_to_str(PI_INT))); 

Edit: tôi có thể làm một số cơ bản thời gian biên dịch in với constexpr s, ít nhất là trên gcc bằng cách làm một cái gì đó giống như

template <int v> 
struct display_non_zero_int_value; 

template <> 
struct display_non_zero_int_value<0> { static constexpr bool foo = true; }; 

static constexpr int v = 1; 

static_assert(v == 0 && display_non_zero_int_value<v>::foo, "v == 0"); 

cung cấp cho tôi error: incomplete type ‘display_non_zero_int_value<1>’ used in nested name specifier static_assert(v == 0 && display_non_zero_int_value<v>::foo, "v == 0");. (ICPC, mặt khác, là ít hữu ích, và chỉ nói error: incomplete type is not allowed) Có cách nào để viết một macro có thể khái quát này để tôi có thể làm điều gì đó như

constexpr int PI_INT = 4; 
PRINT_VALUE(PI_INT) 

và nhận được một thông báo lỗi có liên quan đến 4, bằng cách nào đó?

+2

Không đăng câu trả lời này vì tôi không có bằng chứng, nhưng tôi nhớ đã cố gắng làm điều này trong quá khứ và tôi nghĩ tiêu chuẩn nói rằng static_assert phải lấy chuỗi ký tự, và kết quả là bạn có thể 't sử dụng một biểu thức constexpr thay thế. lấy làm tiếc. – je4d

+0

Lưu ý rằng bản sửa lỗi của bạn không thực sự sử dụng 'static_assert'. Nó chỉ là tái tạo lại ý tưởng cơ bản của một cấu trúc không làm gì ngoài việc vượt qua hoặc thất bại. Điều mà "in ấn" cũng phải thực hiện kiểm tra, vì vậy bạn đang gặp khó khăn trong việc giải quyết toàn bộ vấn đề với SFINAE. – Potatoswatter

Trả lời

11

Trích dẫn ngữ pháp đưa ra cho tờ khai trong §7/​​1 [dcl.dcl]:

static_assert-declaration:

static_assert (constant-expression , string-literal) ;

Tiêu chuẩn nói nó có phải là một chuỗi chữ, vì vậy bạn không gặp may; bạn không thể sử dụng hàm constexpr để xây dựng thông báo lỗi của mình.

Tuy nhiên, bạn có thể sử dụng bất kỳ ma thuật tiền xử lý nào bạn muốn tạo một chuỗi ký tự để đi vào đó. Nếu PI_INT là một #define thay vì một constexpr int, bạn có thể sử dụng một cái gì đó như thế này:

#define PI_INT 4 
#define pi_err_str_(x) #x 
#define pi_err_str(x) pi_err_str_(x) 
#define pi_int_err "PI_INT must be 3, not " pi_err_str(PI_INT) 

static_assert(PI_INT == 3, pi_int_err); 

đầu ra:

error: static assertion failed: "PI_INT must be 3, not 4"


Sửa để phản ứng lại bình luận của OP và cập nhật câu hỏi

Is there a way to write a macro that can generalize this so that I can do something like ... and get an error message that involves 4, somehow?

Chắc chắn, một chút tiền xử lý hoặc ma thuật có thể khái quát rằng, giả sử bạn đang hạnh phúc để được phụ thuộc vào hành vi thông báo lỗi biên dịch cụ thể:

#define strcat_(x, y) x ## y 
#define strcat(x, y) strcat_(x, y) 
#define PRINT_VALUE(x) template <int> struct strcat(strcat(value_of_, x), _is); static_assert(strcat(strcat(value_of_, x), _is)<x>::x, ""); 

constexpr int PI_INT = 4; 
PRINT_VALUE(PI_INT) 

stackoverflow/13465334.cpp:20:1: error: incomplete type ‘value_of_PI_INT_is<4>’ used in nested name specifier

Đối với các trình biên dịch khác, tôi không biết những gì bạn có thể làm ngay, nhưng bạn có thể muốn xem xét một bản sao của static_assert.hpp của boost để xem có bất kỳ thủ thuật nào được sử dụng ở đó có thể được sử dụng để lấy một khuôn mẫu được đánh giá arg đã in hay không.

+0

Điều đó trả lời hai phần ba cuối cùng của câu hỏi của tôi. Thứ ba đầu tiên, về việc in các giá trị 'constexpr' tại thời gian biên dịch, không rõ ràng. Xem chỉnh sửa tôi vừa tạo. –

+0

Bất kỳ cách nào để làm việc này tại phạm vi khối (để in bên trong chức năng templated)? – mxmlnkn

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