2016-01-21 20 views
5

Đoạn mã sau đây đã được biên dịch thành công với gcc 5.3.0 nhưng không biên dịch được bằng clang 3.7.0. Tôi đã sử dụng các trình biên dịch coliru trực tuyến với các tùy chọn dòng lệnh giống nhau trong cả hai trường hợp: -std = C++ 14 -O2 -Wall -pedantic -pthread.Đối số chỉ được sử dụng trong ngữ cảnh không được đánh giá bên trong nội dung của hàm constexpr

#include <cstdio> 

// Definition of constexpr function 'foo'. 
constexpr std::size_t foo(const int& arg_foo) { return sizeof(arg_foo); } 

// Definition of function 'test'. 
void test(const int& arg) 
{ 
    // The following line produces an error with clang. 
    constexpr std::size_t res_foo = foo(arg); 

    // Print the result returned by the 'foo' function. 
    std::printf("res_foo = %lu\n", res_foo); 
} 

// Definition of function 'main'. 
int main(int argc, const char* argv[]) 
{ 
    // Test function call. 
    test(argc); 

    // Return statement. 
    return 0; 
} 

kêu vang từ chối yêu cầu với các lỗi sau:

error: constexpr variable 'res_foo' must be initialized by a constant expression 
constexpr size_t res_foo = foo(arg); 
          ~~~~^~~~ 

Bởi vì sự khác biệt này giữa hai trình biên dịch, tôi tự hỏi nếu điều này là một phần giá trị của mã. Nếu không, tôi muốn hiểu rõ hơn về lý do tại sao điều này xảy ra.

+0

lỗi gcc, một trong nhiều khi nói đến constexpr – TemplateRex

+0

@TemplateRex Nhưng theo cách nào thì 'foo' vi phạm bất kỳ quy tắc nào của hàm constexpr? – Archimaredes

+0

@Archimaredes không, lỗi là 'arg' trong' test' không phải là 'constexpr' – TemplateRex

Trả lời

1

Bạn đang trộn các giá trị constconstexpr cùng nhau. Định nghĩa của constexpr là một giá trị được biết đến tại thời gian biên dịch. Nhưng biến số argc chỉ được biết trong thời gian chạy (đó là một số đối số được truyền cho tệp thi hành của bạn). Vì vậy, bạn không thể gán nó cho biến số constexpr khác - res_foo. Việc xóa constexpr khỏi định nghĩa res_foo sẽ làm cho mã của bạn có thể được biên dịch.

Sự khác biệt giữa constconstexpr có thể được đơn giản hóa đến một cái gì đó như thế này:
const - Tôi sẽ không thay đổi giá trị này
constexpr - Giá trị này được biết đến tại thời gian biên dịch Tôi sẽ không để thay đổi nó

Đoán của tôi là GCC có thể biên dịch mã này với O2 vì bạn không sử dụng đối số arg_foo và kích thước của nó được biết tại thời gian biên dịch. Nhưng nó vẫn còn là cú pháp không chính xác - trình biên dịch sẽ phát ra một lỗi, vì giá trị non-constexpr được gán cho một biến constexpr.

+1

Tôi nghĩ anh ta biết về điều này, câu hỏi của anh ta là vì anh ta không bao giờ thực sự sử dụng giá trị' argc', anh ta chỉ lấy 'sizeof ', là một biểu thức liên tục. – TartanLlama

+0

@TartanLlama lý do tại sao gcc có thể biên dịch mã này với O2: nó bỏ qua đối số vì nó không được sử dụng và trả về một giá trị thời gian biên dịch nổi tiếng. Nhưng nó vẫn còn không chính xác về cú pháp - trình biên dịch sẽ phát ra một lỗi vì giá trị không 'constexpr' được gán cho biến 'constexpr'. – DennisS

+0

Tôi biết nó vẫn còn sai về cú pháp, nhưng tôi nghĩ đó là những gì bạn nên giải quyết trong câu trả lời. – TartanLlama

0

Chương trình được định dạng tốt, vì foo(arg) là biểu thức hằng số cốt lõi prvalue như được định nghĩa trong C++ 14 5.20/2. Đặc biệt, không có chuyển đổi từ rvalue-to-rvalue trong quá trình đánh giá, điều này sẽ làm cho nó không phải là một biểu thức liên tục.

+0

Không thực sự. Đánh giá yêu cầu đánh giá * id-expression * 'arg', chạy afoul của [expr.const] /2.9:" Một biểu thức điều kiện e là một biểu thức liên tục lõi trừ khi đánh giá e, theo các quy tắc của trừu tượng máy (1.9), sẽ đánh giá một trong các biểu thức sau đây: [...] một biểu thức id đề cập đến biến hoặc thành phần dữ liệu của loại tham chiếu trừ khi tham chiếu có khởi tạo trước và - nó được khởi tạo với biểu thức không đổi hoặc - nó là một thành viên dữ liệu không tĩnh của một đối tượng có tuổi thọ bắt đầu trong quá trình đánh giá của e ". –

+0

5/8 "Toán hạng chưa được đánh giá không được đánh giá." – aschepler

+0

Có, nó không được đánh giá bên trong 'foo'.Nhưng nó được đánh giá bên ngoài nó để vượt qua đối số. Bước đầu tiên để đánh giá 'foo (arg)' là đánh giá 'foo' và' arg'. –

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