2017-10-29 14 views
10

Tôi có một vấn đề với "nếu constexpr" trong một lambda templated. Vì lợi ích của các đối số chúng ta hãy bỏ qua cách tôi đến đó, nhưng tôi có một foo struct được định nghĩa một cách nào đó để dẫn đến một cái gì đó như sau:False-chi nhánh của nếu constexpr không bị loại bỏ trong templated lambda

template<bool condition> 
struct foo { 
    int a; 

    // Only contains b if condition is true 
    int b; 
} 

Bây giờ tôi có thể định nghĩa một hàm thtemplate templated

template<bool condition> 
void print_fun(foo & obj) { 
    /* Do something with obj.a */ 
    if constexpr(condition) 
     /* Do something with obj.b */ 
}; 

Instantiating chức năng này và sử dụng nó sẽ biên dịch, nếu tham số constexpr để foo là giống như một đến print_fun, tức là

constexpr bool no = false; 
foo<no> obj = {}; 
print_fun<no>(obj); 

Điều này biên dịch vì nhánh giả bị loại bỏ bên trong một thực thể mẫu, và do đó không có vấn đề gì với việc sử dụng obj.b bên trong print_fun.

Tuy nhiên, nếu tôi xác định một biểu thức lambda tương tự như sau:

template<bool condition> 
auto print_lambda = [](foo & obj) { 
    /* Do something with obj.a */ 
    if constexpr(condition) 
     /* Do something with obj.b */ 
}; 

và nhanh chóng nó:

constexpr bool no = false; 
foo<no> obj = {}; 
print_lambda<no>(obj); 

sau đó chi nhánh sai không bỏ đi và trình biên dịch mang lại cho tôi

'b': không phải là thành viên của 'foo'

Hành vi này có dự định không, nó có xảy ra trên các trình biên dịch khác không? Tôi có làm gì sai không? Hoặc là một lỗi trong trình biên dịch? (Microsoft Visual Studio Phiên bản 15.4.1, gcc 7.2)

Kiểm tra thử nghiệm của tôi here với gcc, nơi nó không biên dịch cho hàm hoặc hàm hoặc.

Chỉnh sửa: Đây là mã của một ví dụ tối thiểu của tôi, tôi không biết rằng liên kết bên ngoài sẽ không đủ. Điều này biên dịch trên Visual Studio 15.4.1, ngoại trừ dòng ghi chú. foo_bar thay thế cho số foo trong mô tả của tôi.

#include <iostream> 

constexpr bool no = false; 

struct foo { 
    int x; 
}; 

struct bar { 
    int y; 
}; 

template <bool, typename AlwaysTy, typename ConditionalTy> 
struct Combined : AlwaysTy {}; 

template <typename AlwaysTy, typename ConditionalTy> 
struct Combined<true, AlwaysTy, ConditionalTy> : AlwaysTy, ConditionalTy {}; 

using foo_bar = Combined<no, foo, bar>; 

template<bool condition> 
void print_fun(foo_bar & obj) { 
    std::cout << obj.x << std::endl; 
    if constexpr(condition) 
     std::cout << obj.y << std::endl; 
}; 

template<bool condition> 
auto print_lambda = [](foo_bar & obj) { 
    std::cout << obj.x << std::endl; 
    if constexpr(condition) 
     std::cout << obj.y << std::endl; 
}; 

int main(int argc, char ** argv) { 
    foo_bar obj = {}; 
    print_lambda<no>(obj); // Does not compile 
    print_fun<no>(obj); 
} 
+1

"constexpr dùng để tạo foo". constexprs không tạo ra bất cứ điều gì. Nhiều phần câu hỏi của bạn khó hiểu và không thể được phân tích cú pháp. Bạn cần phải bao gồm một [mcve] cụ thể thể hiện lỗi biên dịch mà bạn đang yêu cầu, để mọi người có thể tự xem nó, thay vì phải đoán nó là gì. Và bạn phải bao gồm nó *** trong câu hỏi chính nó ***, thay vì một liên kết đến một số trang web bên ngoài có thể ngừng làm việc bất cứ lúc nào, làm cho câu hỏi vô nghĩa. Hầu hết mọi người trên stackoverflow.com bỏ qua các liên kết bên ngoài trong câu hỏi, vì lý do đó. –

+0

Tôi đã chỉnh sửa câu hỏi của mình để bao gồm ví dụ. Xin lỗi vì sự nhầm lẫn, tôi chỉ không muốn đi vào chi tiết về cách foo đến được khác nhau dựa trên một constexpr, nhưng tôi hy vọng nó rõ ràng bây giờ. –

Trả lời

7

Theo mã liên kết,

template<bool condition> 
void print_fun(foo_bar & obj) { 
    std::cout << obj.x << std::endl; 
    if constexpr(condition) 
     std::cout << obj.y << std::endl; 
} 

Vấn đề là với if constexpr được sử dụng, báo cáo kết quả std::cout << obj.y << std::endl; là vô hình thành cho mỗi instantiation thể của mẫu print_fun; tức là không có vấn đề gì giá trị của condition nó chỉ là luôn luôn hình thành.

Lưu ý: báo cáo kết quả bỏ đi không thể vô hình thành cho mỗi chuyên ngành có thể:

Cách giải quyết chung cho một nhận tất cả tuyên bố như là một biểu thức kiểu phụ thuộc vào đó luôn luôn là sai:

Để khắc phục sự cố, bạn có thể làm cho câu lệnh phụ thuộc vào tham số mẫu, ví dụ:

template <bool condition> 
using foo_bar = Combined<condition, foo, bar>; 

template<bool condition> 
void print_fun(foo_bar<condition> & obj) { 
    std::cout << obj.x << std::endl; 
    if constexpr(condition) 
     std::cout << obj.y << std::endl; 
} 

và sử dụng nó như

foo_bar<no> obj = {}; 
print_fun<no>(obj); 

Bây giờ cho obj.y, obj là loại foo_bar<condition>, mà phụ thuộc vào các tham số mẫu condition.

LIVE

+0

Thật thú vị tôi thấy điều này bây giờ biên dịch trên các ví dụ sống, nhưng nó làm cho không có sự khác biệt khi biên dịch mã trong Visual Studio. Hàm và hàm functor như trước, trong khi lambda vẫn phát ra cùng một cảnh báo. –

+0

@ HannoBänsch Tôi không có VS, vậy tin nhắn là gì? (Nó chỉ là một cảnh báo?) BTW Tôi đã thử nghiệm và mã biên dịch với cả GCC và Clang. – songyuanyao

+0

Lỗi tương tự như được đề cập trong câu hỏi. Tôi hiểu lý do tại sao trước đây nó không nên đã làm việc, nhưng bây giờ có vẻ như nhiều khả năng rằng VS có một lỗi, nếu constexpr thậm chí không được hỗ trợ một vài tháng trước đây. –

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