2015-01-02 11 views
35

gcc biên dịch đoạn mã sau mà không cần cảnh báo:Đây có phải là phần mở rộng trình biên dịch phù hợp để xử lý các hàm thư viện chuẩn không phải là constexpr như constexpr không?

#include <cmath> 

struct foo { 
    static constexpr double a = std::cos(3.); 
    static constexpr double c = std::exp(3.); 
    static constexpr double d = std::log(3.); 
    static constexpr double e1 = std::asin(1.); 
    static constexpr double h = std::sqrt(.1); 
    static constexpr double p = std::pow(1.3,-0.75); 
}; 

int main() 
{ 
} 

Không ai trong số các chức năng thư viện chuẩn được sử dụng trên được chức năng constexpr, chúng tôi được phép sử dụng chúng ở đâu một liên tục biểu được yêu cầu từ cả hai the draft C++11 standarddraft C++14 standard phần 7.1.5[dcl.constexpr]:

[...] Nếu nó được khởi tạo bởi một cuộc gọi hàm tạo, cuộc gọi đó phải là biểu thức liên tục (5.19). Nếu không, hoặc nếu một specifier constexpr được được sử dụng trong một tuyên bố tham khảo, mọi biểu hiện đầy đủ xuất hiện trong initializer của nó sẽ là một biểu thức hằng. [...]

Ngay cả khi sử dụng -std=c++14 -pedantic hoặc -std=c++11 -pedantic không có cảnh báo là được tạo (see it live). Sử dụng -fno-builtin sản xuất lỗi (see it live) mà chỉ ra rằng phiên bản builtin các chức năng thư viện chuẩn bị đối xử như thể họ nơi constexpr

Trong khi clang không cho phép mã với bất kỳ sự kết hợp của cờ tôi đã cố gắng.

Vì vậy, đây là tiện ích mở rộng gcc để xử lý ít nhất một số chức năng dựng sẵn như thể chúng là chức năng constexpr mặc dù tiêu chuẩn không yêu cầu chúng rõ ràng. Tôi đã mong đợi ít nhất sẽ nhận được một cảnh báo trong chế độ tuân thủ nghiêm ngặt, đây có phải là một phần mở rộng phù hợp không?

Trả lời

35

TL; DR

Trong C++ 14 này được một cách rõ ràng không được phép, mặc dù trong 2011 nó xuất hiện như trường hợp này sẽ được phép một cách rõ ràng. Nó không rõ ràng nếu C++ 11 này rơi xuống dưới as-if rule, tôi không tin nó vì nó thay đổi hành vi quan sát nhưng điểm đó không được làm sáng tỏ trong vấn đề tôi tham khảo dưới đây.

Chi tiết

Câu trả lời cho câu hỏi này đã thay đổi với tình trạng phát triển của LWG issue 2013 mở đầu bằng:

Giả sử rằng một chức năng cụ thể không được gắn thẻ như constexpr trong tiêu chuẩn , nhưng rằng, trong một số thực hiện cụ thể, có thể để viết nó trong các ràng buộc constexpr. Nếu một người triển khai gắn thẻ một hàm như constexpr, có phải là vi phạm tiêu chuẩn hoặc đó có phải là tiện ích mở rộng phù hợp không?

Trong C++ 11 nó là không rõ ràng nếu như-nếu quy tắc phép này nhưng đề nghị orignal sẽ cho phép một cách rõ ràng một khi nó đã được chấp nhận và chúng ta có thể nhìn thấy dưới đây trong báo cáo lỗi gcc Tôi tham khảo, đây là giả định của nhóm gcc.

Sự đồng thuận để cho phép điều này được chuyển vào năm 2012 và đề xuất đã thay đổi và trong C++ 14 đây là tiện ích mở rộng không phù hợp. Này được phản ánh trong dự thảo C++ 14 phần chuẩn 17.6.5.6[constexpr.functions] mà nói:

[...] An thực hiện sẽ không tuyên bố bất kỳ tiêu chuẩn chức năng thư viện chữ ký như constexpr trừ các đối tượng nơi mà nó là rõ ràng yêu cầu. [..]

và mặc dù đọc khắt khe của điều này dường như để lại một số phòng lung để điều trị một BUILTIN ngầm như thể nó là một constexpr chúng ta có thể nhìn thấy từ đoạn trích sau đây trong vấn đề là nhằm ngăn chặn sự phân kỳ trong việc triển khai kể từ id đang entical có thể tạo ra hành vi khác nhau khi sử dụng SFINAE (tôi nhấn mạnh):

Một số lo ngại bày tỏ khi trình bày cho ban đầy đủ cho các cuộc bỏ phiếu đến tình trạng WP rằng vấn đề này đã được giải quyết mà không đủ nghĩ hậu quả cho triển khai thư viện phân tách, vì người dùng có thể sử dụng SFINAE để quan sát hành vi khác với cách khác mã giống hệt.

Chúng ta có thể nhìn thấy từ báo cáo lỗi gcc [C++0x] sinh vs asinh vs constexpr mà nhóm dựa trên độ phân giải đề xuất trước đó của LWG 2013 mà nói:

[...] Ngoài ra, một thực hiện có thể tuyên bố bất kỳ chức năng để được constexpr nếu định nghĩa của chức năng đáp ứng các cần thiết chế [...]

khi quyết định có sự thay đổi này cho các hàm toán học được phép ở khắt khe c chế độ onformance.

Theo tôi có thể nói điều này sẽ trở thành phù hợp nếu chúng tôi nhận được cảnh báo ở chế độ tuân thủ nghiêm ngặt, tức là sử dụng -std=c++11 -pedantic hoặc nếu bị vô hiệu hóa ở chế độ này.

Lưu ý, tôi đã thêm nhận xét vào báo cáo lỗi giải thích rằng độ phân giải đã thay đổi do vấn đề này ban đầu được giải quyết.

Jonathan Wakely pointed out trong một câu hỏi khác một gần đây discussion và có vẻ như có khả năng báo cáo lỗi gcc sẽ được mở cửa trở lại để giải quyết vấn đề phù hợp này.

gì về intrinsics

Compiler intrinsics không thuộc tiêu chuẩn và để như xa như tôi có thể nói họ nên được miễn quy tắc này, vì vậy sử dụng:

static constexpr double a = __builtin_cos(3.); 

nên được cho phép. Câu hỏi này đã đưa ra trong báo cáo lỗi và ý kiến ​​của Daniel Krügler là:

[...] chức năng thư viện và intrinsics khác có lẽ có thể được coi là trường hợp ngoại lệ, bởi vì họ không phải là "giải thích được" bởi quy tắc ngôn ngữ thông thường.

+0

@Walter Tôi đã thêm phần 'LT; DR'. Hãy cho tôi biết nếu có điểm khác tôi có thể làm rõ. –

+0

Còn nội tại thì sao? – Columbo

+0

Tôi không nghĩ rằng nó hữu ích để nói về trình biên dịch nội tại. Tất cả các tên bắt đầu bằng '__' được dành riêng cho việc triển khai thực hiện và việc triển khai thực hiện định nghĩa ngữ nghĩa của chúng. Nó hoàn toàn hợp lý cho ngữ nghĩa của các hàm thực hiện cụ thể, cho dù chúng là intrinisics hay không, được định nghĩa là 'constexpr', hoàn toàn theo ý của người thực hiện. –

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