2017-07-03 18 views
5

Tôi đang cố gắng tìm hiểu về các khái niệm Lite TS mà chưa được sáp nhập vào tiêu chuẩn. Tôi đang bối rối về hành vi của các xung đột ngắn mạch trong các khái niệm cơ quan.C++ Khái niệm Lite: Ngắn mạch trong các khái niệm cơ quan

Dưới đây là một ví dụ nhỏ:

#include <type_traits> 
#include <iostream> 

template <typename T, typename ... Ts> concept bool myconcept = 
(sizeof...(Ts) == 0) || (std::is_same_v<T, std::common_type_t<Ts...>>); 

template <typename ... Ts> 
void myfunc(Ts ... args) requires myconcept<int, Ts...> { 
    (... , (std::cout << args << std::endl)); 
} 

int main() { 
    myfunc(); 
    return 0; 
} 

Biên soạn với gcc 7.1 và -fconcepts, cung cấp cho các lỗi:

error: cannot call function 'void myfunc(Ts ...) requires myconcept<int, Ts ...> [with Ts = {}]' 

Trong ví dụ này, std::common_type_t<Ts...> không tồn tại kể từ khi struct std::common_type<Ts...> không có một thành viên type nếu Ts = {}. Tuy nhiên, tôi nghĩ rằng điều này sẽ biên dịch bởi vì tài liệu cppereference.com về concepts and constraints khẳng định rằng

Disjunctions are evaluated left to right and short-circuited (if the left constraint is satisfied, template argument deduction into the right constraint is not attempted).

Kể từ sizeof...(Ts) == 0 là hài lòng, khấu trừ mẫu tranh luận không nên cố gắng vào các hạn chế thứ hai và yêu cầu myconcept<int, Ts...> nên hài lòng.

Kỳ lạ thay, đặt yêu cầu trực tiếp vào chức năng declarator làm cho chương trình để biên dịch:

#include <type_traits> 
#include <iostream> 

template <typename ... Ts> 
void myfunc(Ts ... args) requires (sizeof...(Ts) == 0) || (std::is_same_v<int, std::common_type_t<Ts...>>) { 
    (... , (std::cout << args << std::endl)); 
} 

int main() { 
    myfunc(); 
    return 0; 
} 

Có một lời giải thích tốt cho hành vi này? Cảm ơn.

+0

"Các khái niệm Lite TS mà vẫn chưa được sáp nhập vào các tiêu chuẩn" Tôi có thể tìm thấy thông tin này ở đâu? Thông tin cuối cùng của tôi là nó không được chấp nhận ... – Klaus

Trả lời

2

Giải thích của giáo dân xuất hiện trên cppreference là chính xác. Chọn từ ngữ từ n4674 draft là khá rõ ràng cũng như:

A conjunction is a constraint taking two operands. A conjunction of constraints is satisfied if and only if both operands are satisfied. The satisfaction of a conjunction’s operands are evaluated left-to-right; if the left operand is not satisfied, template arguments are not substituted into the right operand, and the constraint is not satisfied. […]

(. Từ các hoạt động logic 17.10.1.1 [temp.constr.op] §2) Kể từ khi tất cả các từ ngữ đó một cách chính xác thiết lập như thế nào chúng tôi đi từ khái niệm và các mẫu để kết hợp hoặc tách rời các ràng buộc nguyên tử là khá dài, chúng ta sẽ dính vào lời giải thích của giáo dân.

Is there a good explanation for this behavior? Thanks.

Do đó, việc thực hiện GCC khái niệm là rất nhiều thử nghiệm. Là một workaround bạn có thể cấu trúc lại phần vấn đề vào khái niệm riêng của mình:

template<typename T, typename... Ts> 
concept bool refactored = std::is_same_v<T, std::common_type_t<Ts...>>; 

template<typename T, typename... Ts> 
concept bool myconcept = sizeof...(Ts) == 0 || refactored<T, Ts...>; 

Coliru demo