2012-11-08 23 views
11

trong khi duyệt một trong các câu hỏi cũ của tôi trên constexpr tôi vấp vào một nhận xét quan trọng (IMHO). Về cơ bản nó nắm tới: (điều này là hợp pháp C++ 11 :()Tại sao constexpr hoạt động cho các chức năng không tinh khiết

constexpr double f(bool b) 
{ 
return b? 42:42/(rand()+1); // how pure is rand ;) 
} 

Câu hỏi của tôi là những gì lý do này được cho phép theo tiêu chuẩn Kể từ khi Im một fan hâm mộ lớn của tính minh bạch referential Tôi hy vọng. họ có lý do chính đáng :) và tôi muốn biết điều đó.

BTW có liên quan Q nhưng hầu hết các A thậm chí không đề cập đến điều tinh khiết, hoặc khi họ làm họ không xác định lý do tại sao std cho phép điều này. Relation between constexpr and pure functions

+1

rand() là một constexpr? – Yakk

+1

no it isnt, đó là lý do tại sao tôi đặt;) trong các chú thích – NoSenseEtAl

Trả lời

7

Từ khóa constexpr trong định nghĩa chức năng cho trình biên dịch rằng chức năng này thể được thực hiện tại thời gian biên dịch nếu tất cả các đối số và các biến được biết tại thời gian biên dịch riêng của mình. Tuy nhiên, không có sự đảm bảo như vậy, ví dụ khi một số giá trị có thể được biết chỉ khi chạy, trong trường hợp này, hàm sẽ được thực hiện khi chạy.

Tuy nhiên, nó không có gì để làm với tinh khiết hoặc bất tịnh, vì những điều khoản này ngụ ý rằng đầu ra phụ thuộc vào các yếu tố đầu mà thôi, và không có vấn đề bao nhiêu lần bạn gọi hàm với cùng các giá trị của các thông số đầu vào , đầu ra sẽ giống nhau mọi lúc, bất kể nó được tính tại thời gian biên dịch hay thời gian chạy.

Ví dụ,

constexpr int add(int a, int b) { return a + b; } //pure! 

const int a = 2, b = 3; //const 
int c = 2, d = 3;  //non-const 

//we may read update c and d here! 

const int v1 = add(2,3); //computed at compile-time 
const int v2 = add(a,3); //computed at compile-time 
const int v3 = add(2,b); //computed at compile-time 
const int v4 = add(a,b); //computed at compile-time 

const int v3 = add(c,3); //computed at runtime 
const int v3 = add(c,b); //computed at runtime 
const int v3 = add(a,d); //computed at runtime 
const int v3 = add(c,d); //computed at runtime 

Lưu ý rằng đây là một chức năng add tinh khiết cho dù nó được tính tại thời gian biên dịch hoặc chạy.

+1

Bất kỳ hàm thuần nào có thể được đánh giá tại thời gian biên dịch theo quy tắc as-if, bất kể 'constexpr'. Nó được gọi là gấp liên tục. 'Constexpr' trong ví dụ của bạn dường như không tạo ra bất kỳ sự khác biệt nào cả. – Potatoswatter

+1

@Potatoswatter: Bạn có nghĩa là chúng ta có thể viết 'std :: array a;' ngay cả khi 'add' không phải là' constexpr'? Tôi không nghĩ vậy. – Nawaz

+1

Tôi có nghĩa là trong ví dụ của bạn: v). (Câu trả lời của bạn dường như không giải quyết được bối cảnh biểu hiện liên tục chút nào.) Tôi [mở một câu hỏi] (http://stackoverflow.com/questions/14472359/why-do-we-need-to-mark-functions-as -constexpr? lq = 1) về việc liệu 'std :: array ' sẽ là một điều xấu. – Potatoswatter

6

Vì đối với một số miền của tham số đầu vào, đường dẫn không tinh khiết sẽ không bao giờ được thực hiện. Đối với tên miền đó, constexpr sẽ hoạt động tốt.

Ví dụ: chức năng của bạn có thể có nhánh đơn giản và nhánh phức tạp hơn. Và bạn có thể chỉ định rằng hàm của bạn có thể sử dụng được trong các biểu thức không đổi, các đối số hàm phải như vậy và điều kiện đó được đáp ứng, sinh ra cho nhánh đơn giản trong hàm của bạn luôn thuần khiết.

Một tác dụng phụ hữu ích của việc này là bạn có thể gây ra lỗi trong quá trình tính toán liên tục. Tức là nếu điều kiện tiên quyết trong nhánh đơn giản bị vi phạm, bạn có thể gây ra việc đánh giá biểu thức không tinh khiết, kích hoạt một lỗi thời gian biên dịch (một khẳng định hoặc ngoại lệ là một ý tưởng tốt ở đây, vì nó tiếp tục khiếu nại khi hàm được gọi trong một ngữ cảnh thời gian chạy).

9

Trong tiêu chuẩn, yêu cầu liên quan được chôn dưới danh sách yêu cầu chính cho các chức năng constexpr. Nó nằm trong §7.1.5/5:

Đối với một hàm constexpr, nếu không có giá trị đối số hàm nào, hàm thay thế hàm sẽ tạo ra biểu thức không đổi (5.19), chương trình không đúng định dạng; không cần chẩn đoán.

§5.19 xác định các yêu cầu cho biểu thức không đổi, sao cho bạn không thể gọi rand().

Hạn chế thoải mái cho phép bạn có các chức năng có điều kiện thuần túy. Ví dụ của bạn f(true) là một đối số mẫu hợp lệ, nhưng f(false) thì không.

Mặt khác, tất nhiên, trình biên dịch sẽ không xác minh rằng chức năng constexpr thực sự có thể được sử dụng cho mục đích đã định của nó. Bạn cần phải viết các trường hợp thử nghiệm.

Ah, câu trả lời của câu trả lời cũng chính xác. (Nhưng điều này được diễn đạt đơn giản hơn.)

+1

Đây là câu trả lời đúng. – Omnifarious

+1

Nó cũng là một câu trả lời tốt hơn vì nó trích dẫn phần có liên quan của tiêu chuẩn cũng như đưa ra một lời giải thích tốt về ý nghĩa của nó. – Omnifarious

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