2015-04-08 18 views
11

tôi đã viết các hàm mẫu sau đây, mà kiểm tra xem một container tùy ý chứa một yếu tố cụ thể:Enable mẫu chức năng nếu lớp có chức năng thành viên cụ thể

template<template<class, class...> class container_t, class item_t, class... rest_t> 
bool contains(const container_t<item_t, rest_t...> &_container, const item_t &_item) { 
    for(const item_t &otherItem : _container) { 
     if(otherItem == _item) { return true; } 
    } 
    return false; 
} 

này hoạt động tốt cho hầu hết các container. Tuy nhiên đối với tất cả các loại bộ (và bản đồ), nó là phụ tối ưu vì chúng tôi có thể sử dụng:

template<template<class, class...> class set_t, class item_t, class... rest_t> 
bool contains(const set_t<item_t, rest_t...> &_set, const item_t &_item) { 
    return _set.count(_item) > 0; 
} 

Rõ ràng là chúng tôi không thể sử dụng cả hai mẫu cùng một lúc do không rõ ràng. Bây giờ tôi đang tìm cách sử dụng std::enable_if để bật mẫu đầu tiên nếu container_t không cung cấp chức năng thành viên count và mẫu thứ hai nếu có. Tuy nhiên tôi không thể tìm ra cách kiểm tra một hàm thành viên specif (sử dụng C++ 11).

+4

Nếu bạn sẵn sàng tăng thêm dưới dạng phụ thuộc thì [boost.TTI] (http://www.boost.org/doc/libs/1_57_0/libs/tti/doc/html/index.html) có những gì bạn đang tìm kiếm trong macro 'BOOST_TTI_HAS_MEMBER_FUNCTION'' –

+2

Bạn có chắc chắn muốn thực hiện điều này không? Trong thư viện chuẩn, chúng làm cho bạn hiểu chính xác biểu mẫu 'find' nào bạn muốn sử dụng để làm rõ ràng khi bạn đang thực hiện tìm kiếm tuyến tính và khi bạn đang sử dụng một cơ chế hiệu quả hơn. Một lưu ý phụ nếu bạn thực sự muốn làm điều này, chắc chắn sử dụng 'find' thay vì' count', nó chỉ tránh bi quan sớm. –

+0

@SimonGibbons: Cảm ơn, nó trông giống như những gì tôi cần. Tuy nhiên tôi không muốn phụ thuộc vào việc tăng cường vào lúc này. – Haatschii

Trả lời

15

C++ 14 tính năng, reimplemented:

template<class...>struct voider{using type=void;}; 
template<class...Ts>using void_t=typename voider<Ts...>::type; 

Một thư viện lập trình meta mini:

template<class...>struct types{using type=types;}; 
namespace details { 
    template<template<class...>class Z, class types, class=void> 
    struct can_apply : std::false_type {}; 
    template<template<class...>class Z, class...Ts> 
    struct can_apply< Z, types<Ts...>, void_t< Z<Ts...> > >: 
    std::true_type 
    {}; 
} 
template<template<class...>class Z, class...Ts> 
using can_apply = details::can_apply<Z,types<Ts...>>; 

can_apply< some_template, args... > thừa hưởng từ true_type iff some_template<args...> là một biểu thức hợp lệ (trong bối cảnh ngay lập tức).

Bây giờ cho vấn đề của bạn:

template<class T, class I> 
using dot_count_type = decltype(std::declval<T>().count(std::declval<I>())); 

template<class T, class I> 
using has_dot_count = can_apply<dot_count_type, T, I>; 

has_dot_count là một lớp học đặc điểm được thừa kế từ true_type iff T.count(I) là một biểu thức hợp lệ.

namespace details { 
    template<class C, class I> 
    bool contains(std::false_type, C const& c, I const& i) { 
    for(auto&& x:c) { 
     if(x == i) { return true; } 
    } 
    return false; 
    } 
    template<class C, class I> 
    bool contains(std::true_type, C const& c, I const& i) { 
    return c.count(i) != 0; 
    } 
} 
template<class C, class I> 
bool contains(C const& c, I const& i) { 
    return details::contains(has_dot_count<C const&,I const&>{}, c, i); 
} 

sử dụng gửi thẻ thay vì SFINAE.

Sử dụng find có vẻ như là một ý tưởng hay hơn .count như một phần. Trong thực tế, trong một trường hợp, bạn nên sử dụng .find khác find. Trong cả hai trường hợp, bạn nên sử dụng using std::end; auto e = end(c);.

Ngoài ra, MSVC 2013 (Tôi không biết về 2015) không xử lý loại SFINAE được sử dụng ở trên. Họ gọi nó là "biểu hiện SFINAE". Họ có các phần mở rộng tùy chỉnh để phát hiện sự tồn tại của một hàm thành viên. Nhưng đó là bởi vì chúng cách xa tiêu chuẩn C++ 11.

+1

VS 2015 (ít nhất là phiên bản xem trước) [không hỗ trợ nó] (http://blogs.msdn.com/b/vcblog/archive/2014/11/17/c-11-14-17-features -in-vs-2015-preview.aspx) –

+0

Cách tiếp cận thú vị. Hoạt động tốt cho tôi (GCC 4.8). Cảm ơn nhiều. – Haatschii

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