2015-09-16 10 views
7

Tôi có một functor mà hoạt động trên một container loại U của phần tử kiểu T như vậyC++ xác định nếu một container có :: tìm()

template<typename T, template<typename...> class U> 
class asserter 
{ 
public: 
    asserter(U<T> &c) : container(c) { }; 
    void operator()(T lhs) 
    { 
     CU_ASSERT(container.find(lhs) != container.end()); 
    }; 
private: 
    U<T> &container; 
}; 

mà tôi có thể sử dụng như

std::set<std::string> a, c; 
... 
asserter<std::string, std::set> ass(c); 
for_each(a.begin(), a.end(), ass); 

Nơi chúng tôi bỏ qua std::includes() cho thời điểm này.

Công trình này tuyệt vời nếu vùng chứa là nơi chứa U::find(). Nếu tôi không muốn quay trở lại std::find(). Mặt khác, tôi muốn sử dụng U::find() hơn std::find() nếu có.

Trong C++ 11 (hoặc 17 nếu cần) tôi có thể xác định xem U::find() có khả dụng (có thể hạn chế STL) cho U và nếu có, hãy sử dụng std::find()?

Trả lời

7

SFINAE về việc biểu thức c.find(value) có được tạo đúng không. Trailing kiểu trả về là C++ 11, và không cần thiết ở đây anyway; nó chỉ làm cho kiểu trả về dễ viết hơn - decltype(c.find(value)) thay vì decltype(std::declval<Container&>().find(std::declval<const T&>())).

Nếu biểu thức không đúng định dạng, quá tải đầu tiên của find_impl bị xóa khỏi tập quá tải, để lại tình trạng quá tải thứ hai là quá tải. Thủ thuật int/long/0 thông thường cho tham số thứ ba làm cho tình trạng quá tải đầu tiên được ưu tiên khi cả hai đều khả thi.

template<class Container, class T> 
auto find_impl(Container& c, const T& value, int) -> decltype(c.find(value)){ 
    return c.find(value); 
} 

template<class Container, class T> 
auto find_impl(Container& c, const T& value, long) -> decltype(std::begin(c)){ 
    return std::find(std::begin(c), std::end(c), value); 
} 

template<class Container, class T> 
auto find(Container& c, const T& value) -> decltype(find_impl(c, value, 0)) { 
    return find_impl(c, value, 0); 
} 

Tuyên bố từ chối trách nhiệm thông thường áp dụng: điều này dựa trên biểu thức SFINAE, hiện không được MSVC hỗ trợ; Microsoft có kế hoạch thêm hỗ trợ trong bản cập nhật cho MSVC năm 2015.

+4

Câu trả lời hữu ích hơn cũng sẽ giải thích lý do mã hoạt động. Ví dụ, tôi đã mong đợi một câu trả lời đã sử dụng SFINAE. Phần 'decltype (...)' có phải là kỹ thuật SFINAE trong C++ 17 (tôi nghĩ cú pháp biểu thức lambda này là C++ 17) không? Ngoài ra, là 'int' được sử dụng để buộc chữ ký đó có sở thích hơn quá tải' long'? –

+0

Tôi có một lo lắng rằng 'std :: find' là để bình đẳng trong khi' std :: set :: find' vv là tương đương. Chúng ta có cần xem xét điều đó không? –

+0

@NickyC Tôi biết rằng * về mặt lý thuyết * chúng khác nhau, nhưng tần suất là trường hợp trong thế giới thực? Tôi nghĩ rằng 'set' và' map' (và họ 'multi') là những người duy nhất quan trọng,' unordered_set' và 'unordered_map' nên sử dụng bình đẳng. –

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