2016-12-05 17 views
28

C++ 1z sẽ giới thiệu "constexpr if" - nếu điều đó sẽ có một nhánh bị loại bỏ, dựa trên điều kiện. Có vẻ hợp lý và hữu ích."constexpr if" vs "if" với tối ưu hóa - tại sao "constexpr" cần thiết?

Tuy nhiên, không thể thực hiện mà không có từ khóa constexpr? Tôi nghĩ rằng trong quá trình biên dịch, trình biên dịch nên biết điều kiện wheter được biết đến trong thời gian biên dịch hay không. Nếu có, ngay cả mức tối ưu hóa cơ bản nhất cũng nên loại bỏ nhánh không cần thiết.

Ví dụ (xem trong godbolt: https://godbolt.org/g/IpY5y5):

int test() { 
    const bool condition = true; 
    if (condition) { 
     return 0; 
    } else { 
     // optimized out even without "constexpr if" 
     return 1; 
    } 
} 

Godbolt thám hiểm cho thấy, rằng ngay cả gcc-4.4.7 với -O0 không biên dịch "return 1", do đó nó đạt được những gì đã hứa với constexpr if. Rõ ràng trình biên dịch cũ như vậy sẽ không thể làm như vậy khi điều kiện là kết quả của hàm constexpr, nhưng thực tế vẫn còn: trình biên dịch hiện đại biết liệu điều kiện là constexpr hay không và không cần tôi để nói cho nó một cách rõ ràng.

Vì vậy, câu hỏi là:

Tại sao "constexpr" cần thiết trong "constexpr if"?

+7

Nó không chỉ là vấn đề tối ưu hóa: nhánh chết của 'constexpr if' được phép là không hợp lệ, nghĩa là, nó sẽ không tự biên dịch. Câu hỏi của bạn là viết tắt. – Quentin

Trả lời

38

Điều này rất dễ giải thích qua ví dụ. Cân nhắc

struct Cat { void meow() { } }; 
struct Dog { void bark() { } }; 

template <typename T> 
void pet(T x) 
{ 
    if(std::is_same<T, Cat>{}){ x.meow(); } 
    else if(std::is_same<T, Dog>{}){ x.bark(); } 
} 

Gọi

pet(Cat{}); 
pet(Dog{}); 

sẽ kích hoạt một lỗi biên dịch (wandbox example), bởi vì cả hai chi nhánh của tuyên bố if phải được well-formed.

prog.cc:10:40: error: no member named 'bark' in 'Cat' 
    else if(std::is_same<T, Dog>{}){ x.bark(); } 
            ~^
prog.cc:15:5: note: in instantiation of function template specialization 'pet<Cat>' requested here 
    pet(Cat{}); 
    ^
prog.cc:9:35: error: no member named 'meow' in 'Dog' 
    if(std::is_same<T, Cat>{}){ x.meow(); } 
           ~^
prog.cc:16:5: note: in instantiation of function template specialization 'pet<Dog>' requested here 
    pet(Dog{}); 
    ^

Thay đổi pet sử dụng if constexpr

template <typename T> 
void pet(T x) 
{ 
    if constexpr(std::is_same<T, Cat>{}){ x.meow(); } 
    else if constexpr(std::is_same<T, Dog>{}){ x.bark(); } 
} 

chỉ yêu cầu các chi nhánh để được parseable - chỉ chi nhánh phù hợp với điều kiện cần phải được định dạng đúng (wandbox example).

Đoạn

pet(Cat{}); 
pet(Dog{}); 

sẽ biên dịch và làm việc như mong đợi.

+1

Cảm ơn bạn. Sự khác biệt giữa "có thể phân tích cú pháp" và "được hình thành tốt" đã bỏ qua tôi trước đây :-) – MateuszL

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