2015-12-15 19 views
5

Giả sử tôi muốn sử dụng std::conditional để xác định loại, nếu loại là vector<...> thì lợi nhuận sẽ là vector<...>::size_type và nếu không thì sẽ là int. (chỉ là một ví dụ).Có thể xây dựng một metafunction lazy_conditional

Một cách ngây thơ để sử dụng std::conditional:

template<class V> struct is_vector : std::false_type{}; 
template<class T> struct is_vector<std::vector<T>> : std::true_type{}; 

template<class C> 
using my_size_type = typename std::conditional< 
    not is_vector<C>::value, 
    int, 
    C::size_type // note that this line only makes sense when condition is false 
>::type; 

Tuy nhiên điều này không thành công vì nếu C là nói một double, double::size_type sẽ đưa ra một lỗi, ngay cả khi đó là việc đánh giá các lựa chọn sai giây.

Vì vậy, tôi tự hỏi nếu có một loại lazy_conditional trong đó câu lệnh giả (hoặc sai thứ hai) không được đánh giá.

Tôi tìm thấy nội dung nào đó ở đây: https://stackoverflow.com/a/5317659/225186 nhưng tôi không biết cách sử dụng ví dụ của mình.


Lưu ý rằng tôi biết làm thế nào để có được những kết quả tương tự mà không sử dụng std::conditional:

template<class V> struct my_size_type{typedef int type;}; 
template<class T> struct my_size_type<std::vector<T>>{typedef std::vector<T>::size_type type;}; 

Câu hỏi đặt ra là nếu có một lazy_conditional rằng bằng cách nào đó gói gọn một std::conditional đó là ngắn mạch.


Sau một số lỗi dùng thử, tôi quản lý để sử dụng ý tưởng trong https://stackoverflow.com/a/5317659/225186 và thực hiện điều này theo sau. Nó cũng làm cho tôi nghĩ rằng không thể viết std::lazy_conditional bởi vì C::size_type không thể xuất hiện ở tất cả trong bất kỳ biểu thức nào là ưu tiên, do đó, cần có hai biểu thức bước.

template<class C, bool B> struct false_case{ 
    typedef void type; 
}; 
template<class C> struct false_case<C, false>{ 
    typedef typename C::size_type type; 
}; 

template<class C> 
using size_type = typename std::conditional< 
    not is_vector<C>::value, 
    int, 
    typename false_case<C, not is_vector<C>::value>::type 
>::type; 

Tôi thậm chí không thể ngưng tụ điều này thành macro, vì mỗi trường hợp khác nhau.

Trả lời

4

Bạn cần mức độ gián tiếp.

template<class T> struct identity { using type = T; }; 

template<class C> 
struct size_type_of : identity<typename C::size_type> { }; 

template<class C> 
using size_type = typename std::conditional<not is_vector<C>::value, 
              identity<int>, 
              size_type_of<C>>::type::type; 

Vấn đề là trì hoãn nhìn C::size_type (bởi instantiating size_type_of<C>) cho đến khi biết nó có một.


Nếu những gì bạn thực sự muốn làm là "C::size_type nếu nó tồn tại, int khác", sau đó std::experimental::detected_or_t là bạn của bạn:

template<class C> 
using size_type_t = typename C::size_type; 

template<class C> 
using size_type_or_default = std::experimental::detected_or_t<int, size_type_t, C>; 
+0

Ok, và tôi đoán nó không thể được gói gọn như một 'lazy_conditional '. Dù sao điều này cũng cho thấy rằng metafunction miễn phí tốt hơn thành viên (có std :: size_type_of :: type thay vì dựa vào T :: size_type) khi có thể (như chức năng miễn phí tốt hơn so với hàm thành viên cho mã chung). – alfC

+0

ah, đây là điều mà tôi khám phá nhiều lần, cuối cùng cũng giống như tôi đã làm ở đây: http://stackoverflow.com/questions/5839357/detect-operator-support-with-decltype-sfinae/18603716# 18603716 – alfC

+0

Trên khả năng tương thích 'detect_or_t': http://stackoverflow.com/questions/36418570/what-compiler-option-library-do-i-need-to-use-detect-or-t-type-trait?noredirect= 1 # comment60486585_36418570 – alfC

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