2015-10-03 13 views
7

Ví dụ:Sử dụng argc trong một constexpr, nó có bắt buộc phải có bất kỳ biểu thức phụ nào liên quan đến một biểu thức không đổi?

int main(int argc, char**) 
{ 
    constexpr int a = argc * 0; 
    (void)a; 
    constexpr int b = argc - argc; 
    (void)b; 
    return 0; 
} 

argc không phải là một biểu thức không đổi, nhưng trình biên dịch vẫn có thể tính toán các kết quả của ab trong thời gian biên dịch (ví dụ: 0) trong cả hai trường hợp.

g++ chấp nhận mã ở trên, trong khi clang và MSVC14 từ chối.

Chuẩn có cho phép trình biên dịch thông minh như g ++ liên quan đến constexpr không?

+1

Tôi nghĩ cả hai trường hợp này nên bị từ chối do [expr.const]/2: 'argc' không phải là biểu thức liên tục cốt lõi vì nó liên quan đến chuyển đổi từ rvalue sang rvalue của biến không được khởi tạo với hằng số biểu hiện. –

+1

Bây giờ tôi đã có cơ hội để suy nghĩ về điều này trông giống như [int a = 1, là || 1 một biểu thức liên tục?] (Http://stackoverflow.com/q/31526278/1708801) –

Trả lời

6

Không phải argc * 0 cũng không argc - argc là các biểu thức không đổi, chuyển đổi lvalue thành rvalue được cho phép trong một số trường hợp nhất định không có trường hợp nào áp dụng ở đây. Nếu chúng ta nhìn vào dự thảo phần tiêu chuẩn C++ 11 5.19 [expr.const], nó đưa ra các ngoại lệ. Nó nói:

Một điều kiện thể hiện là một biểu thức hằng lõi trừ khi nó liên quan đến một trong các cách sau như một subexpression khả năng đánh giá [...]

và có một số viên đạn bao gồm sau đây trên chuyển đổi lvalue-to-rvalue:

chuyển đổi lvalue thành rvalue (4.1) trừ khi nó được áp dụng cho

  • một glvalue của thiếu hoặc liệt kê kiểu đó đề cập đến một đối tượng const non-volatile có một trước khởi, khởi tạo với một biểu thức hằng số, hoặc

  • một glvalue loại đen đó đề cập đến một đối tượng non-volatile định nghĩa với constexpr, hoặc đề cập đến một đối tượng phụ của một đối tượng đó, hoặc

  • một glvalue loại đen đó đề cập đến một đối tượng tạm thời không bay hơi mà tuổi thọ không phải là đã kết thúc, được khởi tạo với một biểu thức không đổi;

Thật thú vị khi lưu ý rằng gcc không chấp nhận đoạn mã sau (see it live):

constexpr int a = argc * 2; 

Vì vậy, nó trông giống như gcc đang nói tôi biết kết quả sẽ là zero và do đó nó thực hiện xếp liên tục và nó không cần phải thực hiện chuyển đổi lvalue-to-rvalue của argc để xác định kết quả.

Rất tiếc, tôi không thấy bất kỳ điều khoản nào trong phần 5.19 cho phép loại ngắn mạch này. Điều này trông rất giống với trường hợp trong int a=1, is a || 1 a constant expression? có báo cáo lỗi nhưng không ai trong nhóm gcc đã trả lời câu hỏi đó. Tôi đã thêm một comment vào báo cáo lỗi cho biết điều này có vẻ liên quan.

bình luận của Mark dưới đây cho thấy đây là một lỗi:

Có cả C++ - trì hoãn gấp chi nhánh trên mà một số nhà phát triển gcc đang làm việc, trong đó sẽ trì hoãn một số tối ưu hóa và có thể sửa lỗi này. Điều quan trọng vì các lý do khác, việc từ chối mã trong câu hỏi này là ưu tiên rất thấp

Các biểu thức liên tục yêu cầu mọi biểu thức con phải là biểu thức không đổi? Không, ví dụ từ 5.19 nó nói: (nhấn mạnh tôi)

Một điều kiện thể hiện là một biểu thức hằng lõi trừ khi nó liên quan đến một trong các cách sau như một subexpression khả năng đánh giá (3.2), nhưng subexpressions của logic AND (5.14), logic OR (5,15), và có điều kiện (5,16) hoạt động mà không phải là đánh giá không được coi là [...]

Vì vậy, sau đây là một biểu thức hằng:

constexpr int a = false && argc * 0; 

argc * 0 không được đánh giá vì && đánh giá từ trái sang phải và ngắn mạch.

+0

Có toàn bộ nhánh C++ - bị trì hoãn gấp mà một số nhà phát triển gcc đang làm việc, điều này sẽ làm chậm trễ một số tối ưu hóa và có thể khắc phục điều này. Điều quan trọng là vì các lý do khác, việc từ chối mã trong câu hỏi này là ưu tiên rất thấp. –

+0

@ downvote xin vui lòng giải thích những gì là sai với câu trả lời của tôi? –

+0

@MarcGlisse cảm ơn bạn đã cung cấp thông tin, tôi không thể nghĩ ra nhiều kịch bản, điều này sẽ dẫn đến một vấn đề nghiêm trọng, ngoài các vấn đề về loại di động. Có bất kỳ thư nào bạn có thể chỉ cho tôi, tôi tò mò muốn hiểu vấn đề tốt hơn. –

0

Bạn có thể có một cái nhìn ở đây: constexpr at cppreference.com

Các cơ sở là một constexpr nên là cái gì đó có thể được xác định một cách rõ ràng tại thời gian biên dịch để trình biên dịch có thể thay thế giá trị của nó trong biểu thức được đánh giá.

Tôi nghĩ rằng vấn đề là argc không phải là một constexpr. Không phải là một cái gì đó trình biên dịch biết. Trong thực tế, bạn có thể thực hiện chính của bạn với một số khác nhau của các đối số. Nếu gcc chấp nhận nó, nó có thể là một lỗi hoặc có thể có một số điều tinh tế liên quan đến tôi không nhận được.

+1

"một cái gì đó có thể được xác định rõ ràng tại thời gian biên dịch", cả hai 'a' và' b' có thể được xác định tại thời gian biên dịch. – emlai

+0

@zenith thật không may các quy tắc không cho phép bỏ qua việc chuyển đổi từ rvalue sang rvalue của 'argc' và do đó nó làm cho nó trở thành một biểu thức không liên tục. –

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