2012-04-29 53 views
22

Tôi cố gắng để khai báo một con trỏ constexpr khởi tạo một số giá trị số nguyên không đổi, nhưng kêu vang được foiling tất cả những nỗ lực của tôi:Constexpr giá trị con trỏ

Cố gắng 1:

constexpr int* x = reinterpret_cast<int*>(0xFF); 

test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression 

Cố gắng 2:

constexpr int* x = (int*)0xFF; 

test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression 

Nỗ lực 3:

constexpr int* x = (int*)0 + 0xFF; 

test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer 

Là những gì tôi đang cố gắng không cho phép bởi thiết kế? Nếu vậy, tại sao? Nếu không, làm thế nào tôi có thể làm điều đó?

Lưu ý: gcc chấp nhận tất cả những điều này.

+2

Tại sao bạn cần một constexpr tại đây? Không constexpr hiệu quả giống như const nếu bạn không sử dụng một chức năng? –

+0

@RobertMason: Ví dụ, nếu đó là một thành viên tĩnh của một lớp, và nó không phải là constexpr, tôi không thể khởi tạo nó trong dòng. – HighCommander4

+1

Có thể một hàm thành viên nội tuyến tĩnh sẽ thích hợp hơn một thành viên dữ liệu. –

Trả lời

18

Như Luc Danton lưu ý, nỗ lực của bạn bị chặn theo quy tắc trong [expr.const]/2 cho biết các biểu thức khác nhau không được phép trong hằng số lõi biểu, bao gồm:

- một reinterpret_cast
- một hoạt động mà có thể có hành vi undefined [chú ý: bao gồm [...] nhất định con trỏ số học [...] - cuối note]

bullet đầu tiên quy định ra ví dụ đầu tiên của bạn. Ví dụ thứ hai bị loại trừ bởi viên đạn đầu tiên ở trên, cộng với quy tắc từ [expr.cast]/4 rằng:

Chuyển đổi được thực hiện bởi [...] a ............................... sử dụng ký pháp đúc của chuyển đổi loại rõ ràng. Các hạn chế và hành vi ngữ nghĩa giống nhau được áp dụng.

Dấu đầu dòng thứ hai được thêm bởi WG21 core issue 1313 và làm rõ rằng số học con trỏ trên con trỏ null không được phép trong biểu thức hằng số. Quy tắc này đưa ra ví dụ thứ ba của bạn. Ngay cả khi những hạn chế này không áp dụng cho biểu thức liên tục lõi, vẫn không thể khởi tạo con trỏ constexpr với giá trị được tạo bằng cách truyền số nguyên, vì biến con trỏ constexpr phải được khởi tạo bằng biểu thức hằng số địa chỉ ., trong đó, bằng [expr.const]/3, phải đánh giá là

địa chỉ của đối tượng có thời lượng lưu trữ tĩnh, địa chỉ của hàm hoặc giá trị con trỏ rỗng.

Định dạng số nguyên cho loại con trỏ không phải là loại nào trong số này.

g ++ chưa thực thi nghiêm ngặt các quy tắc này, nhưng các bản phát hành gần đây đã gần hơn với chúng, vì vậy chúng ta nên giả định rằng cuối cùng nó sẽ triển khai đầy đủ chúng.

Nếu mục tiêu của bạn là khai báo biến mà khởi tạo tĩnh được thực hiện, bạn có thể chỉ cần thả constexpr - cả hai clang và g ++ sẽ phát ra bộ khởi tạo tĩnh cho biểu thức này. Nếu bạn cần cụm từ này là một phần của cụm từ liên tục vì một lý do nào đó, bạn có hai lựa chọn:

  • Tái cấu trúc mã của bạn sao cho dấu intptr_t được truyền qua thay vì một con trỏ và đưa nó vào kiểu con trỏ khi bạn cần phải (bên ngoài biểu thức không đổi) hoặc
  • Sử dụng __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF. Dạng biểu thức chính xác này (với __builtin_constant_p ở phía bên tay trái của toán tử điều kiện) vô hiệu hóa kiểm tra biểu thức liên tục nghiêm ngặt trong vòng tay của toán tử điều kiện, và là một phần mở rộng GNU ít được biết đến, nhưng documented, không cầm tay được hỗ trợ bởi cả gcc và clang.
4

Lý do là thông báo lỗi được cung cấp bởi (cho một lần, rất hữu ích): reinterpret_cast không được phép trong biểu thức liên tục. Nó được liệt kê như là một ngoại lệ rõ ràng trong 5.19 (đoạn 2).

Thay đổi reinterpret_cast thành một diễn viên kiểu C vẫn kết thúc bằng ngữ nghĩa tương đương của reinterpret_cast, do đó không giúp (và thông báo lại rất rõ ràng).

Nếu bạn có cách để lấy con trỏ có giá trị 0, bạn thực sự có thể sử dụng p + 0xff nhưng tôi không thể nghĩ ra cách để có được con trỏ như vậy với biểu thức không đổi. Bạn có thể đã dựa vào giá trị con trỏ null (0 trong ngữ cảnh con trỏ như bạn đã làm, hoặc nullptr) có giá trị 0 về việc triển khai của bạn, nhưng như bạn đã thấy bản thân việc triển khai của bạn từ chối thực hiện điều đó. Tôi nghĩ rằng nó được phép làm điều đó. (Ví dụ: việc triển khai được phép bảo lãnh cho hầu hết các biểu thức không đổi.)

+1

và nó phải là '0xff/sizeof (* x)' mà anh ta thêm vào. –

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