template<class T>struct sink{typedef void type;};
template<class T>using sink_t=typename sink<T>::type;
template<typename T, typename=void>struct my_test:std::false_type{};
template<typename T>struct my_test<T,
sink_t<decltype(
đặt mã tại đây. Lưu ý rằng nó phải "thất bại sớm", tức là trong chữ ký của một hàm, không phải trong cơ thể
)>
>:std::true_type {};
Trên đây tạo ra một thử nghiệm nếu "đặt mã ở đây" có thể được đánh giá.
Để xác định xem "đặt mã ở đây" không thể được đánh giá, phủ nhận kết quả của thử nghiệm.
template<class T>using not_t=std::integral_constant<bool, !T::value>;
not_t< my_test<int> >::value
sẽ là iff "đặt mã ở đây" không thành công ở giai đoạn thay thế. (hoặc bạn có thể làm điều đó theo cách thủ công hơn, bằng cách hoán đổi std::true_type
và std::false_type
ở trên).
Thất bại ở giai đoạn thay thế khác với thất bại chung, và vì nó phải là một biểu thức, bạn có phần hạn chế trong những gì bạn có thể làm. Tuy nhiên, để kiểm tra xem bản sao là có thể, bạn có thể làm:
template<typename T, typename=void>struct copy_allowed:std::false_type{};
template<typename T>struct copy_allowed<T,
sink_t<decltype(
T(std::declval<T const&>())
)>
>:std::false_type {};
và di chuyển:
template<typename T, typename=void>struct move_allowed:std::false_type{};
template<typename T>struct move_allowed<T,
sink_t<decltype(
T(std::declval<T>())
)>
>:std::false_type {};
và chỉ di chuyển:
template<typename T>struct only_move_allowed:
std::integral_constant<bool, move_allowed<T>::value && !copy_allowed<T>::value >
{};
Kỹ thuật chung ở trên dựa vào SFINAE. Lớp đặc điểm cơ bản trông giống như:
template<class T, typename=void> struct whatever:std::false_type{};
Ở đây, chúng ta hãy loại T
, và một (giấu tên) tham số thứ hai chúng tôi mặc định void
. Trong một thư viện sức mạnh công nghiệp, chúng tôi sẽ che giấu điều này như một chi tiết thực hiện (đặc điểm công khai sẽ chuyển tiếp đến loại đặc điểm riêng tư này.
Sau đó, chúng tôi chuyên.
template<typename T>struct whatever<T, /*some type expression*/>:std::true_type{};
lừa là chúng ta làm cho /*some type expression*/
đánh giá để loại void
khi và chỉ khi chúng ta muốn thử nghiệm của chúng tôi để vượt qua. Nếu nó không thành công, chúng ta có thể đánh giá loại không phải là void
hoặc chỉ xảy ra lỗi thay thế.
Nếu và chỉ khi nó đánh giá là void
thì chúng tôi có được true_type
không.
Các sink_t<
một số biểu hiện kiểu >
kỹ thuật mất bất kỳ biểu hiện loại và biến nó thành void
: về cơ bản nó là một thử nghiệm cho sự thất bại thay. sink
trong lý thuyết đồ thị đề cập đến một nơi mà mọi thứ chảy vào, và không có gì xuất hiện - trong trường hợp này, void
là không có gì, và loại chảy vào nó.
Đối với biểu thức loại, chúng tôi sử dụng decltype(
một số biểu thức không loại )
, cho phép chúng tôi đánh giá nó trong ngữ cảnh "giả" mà chúng tôi chỉ vứt bỏ kết quả. Biểu thức không thuộc loại hiện đang được đánh giá chỉ cho mục đích SFINAE.
Lưu ý rằng MSVC 2013 có giới hạn hoặc không hỗ trợ cho bước cụ thể này. Họ gọi nó là "biểu hiện SFINAE". Các kỹ thuật thay thế phải được sử dụng.
Biểu thức không phải loại được đánh giá loại của nó. Nó không thực sự chạy, và nó không gây ra việc sử dụng ODR của bất cứ điều gì. Vì vậy, chúng tôi có thể sử dụng std::declval<X>()
để tạo các bản sao "giả mạo" thuộc loại X
. Chúng tôi sử dụng X&
cho giá trị, X
cho giá trị và X const&
cho giá trị const
.
nỗ lực của 'if (DOES_NOT_COMPILE (DoCopy)) std :: cout <<" Đã qua "<< std :: endl;' nếu nó không được biên dịch là gì? – user1810087
liên quan: Làm thế nào để đơn vị kiểm tra lỗi biên dịch cố ý? tại http://stackoverflow.com/questions/7282350/how-to-unit-test-deliberate-compilation-errors – Arun
@ user1810087 Đó là những gì anh ta đang yêu cầu ... –