2010-01-13 32 views
6

Tôi có chức năng templated hoạt động trên biến kiểu mẫu và nếu giá trị nhỏ hơn 0, đặt giá trị là 0. Điều này hoạt động tốt, nhưng khi loại templated của tôi là unsigned, tôi nhận được một cảnh báo về cách so sánh luôn luôn là sai. Điều này rõ ràng là có ý nghĩa, nhưng kể từ khi được tạo khuôn mẫu, tôi muốn nó là chung cho tất cả các kiểu dữ liệu (đã ký và chưa ký) và không đưa ra cảnh báo.So sánh luôn sai do phạm vi hạn chế ... với các mẫu

Tôi đang sử dụng g + + trên Linux và tôi đoán có cách để ngăn chặn cảnh báo cụ thể đó thông qua tùy chọn dòng lệnh thành g ++, nhưng tôi vẫn muốn nhận cảnh báo trong các trường hợp khác, không có templated . Tôi tự hỏi nếu có một số cách, trong mã, để ngăn chặn điều này, mà không cần phải viết nhiều phiên bản của chức năng?

template < class T > 
T trim(T &val) 
{ 
    if (val < 0) 
    { 
    val = 0; 
    } 
    return (val); 
} 
int main() 
{ 
    char cval = 5; 
    unsigned char ucval = 5; 

    cout << "Untrimmed: " << (int)cval; 
    cval = trim(cval); 
    cout << " Trimmed: " << (int)cval << endl; 

    cout << "Untrimmed: " << (int)ucval; 
    cval = trim(ucval); 
    cout << " Trimmed: " << (int)ucval << endl; 

return (0); 
} 

Trả lời

6
#include <algorithm> 

template<class T> 
T& trim(T& val) { 
    val = std::max(T(0), val); 
    return val; 
} 

Không rõ ràng từ câu hỏi đi qua tham chiếu không phải là thích hợp. Bạn có thể thay đổi gì trên lợi nhuận (void), vượt qua bởi giá trị và trả lại theo giá trị, hoặc đi ngang qua const & và trả lại theo giá trị:

template<class T> 
T trim(T const& val); 

// example use: 
value = trim(value); // likely the most clear solution 

Generalize hơn một chút, mặc dù bên ngoài phạm vi của câu hỏi của bạn:

template<class T> 
T constrain(T const& value, T const& lower, T const& upper) { 
    // returns value if value within [lower, upper] (inclusive end points) 
    // returns lower if value < lower 
    // otherwise returns upper 
    assert(lower <= upper); // precondition 
    return std::min(std::max(value, lower), upper); 
} 

template<class T> 
T constrain_range(T const& value, T const& lower, T const& upper) { 
    // returns value if value within [lower, upper) (exclusive upper) 
    // returns lower if value < lower 
    // otherwise returns upper - 1 
    assert(lower < upper); // precondition 
    if  (value < lower) return lower; 
    else if (value >= upper) return upper - 1; 
    else      return value; 
} 
+0

+1: Vâng, vâng, đó là một giải pháp cho trường hợp đặc biệt này :) –

5

Đối với trường hợp đơn giản được trình bày, bạn sẽ hoàn toàn tốt hơn với giải pháp được trình bày bởi Roger Pate.

Những gì bạn cần cho giải pháp lập trình meta tổng quát là type_traits. Bạn có thể sử dụng những từ tăng, hoặc những người được cung cấp với STL của bạn nếu đủ hiện đại.

namespace detail { 

    template < class T > 
    T trim_impl(T &val, const std::tr1::true_type&) 
    { 
    if (val < 0) 
    { 
     val = 0; 
    } 
    return (val); 
    } 

    template < class T > 
    T trim_impl(T &val, const std::tr1::false_type&) 
    { 
    return (val); 
    } 

} // end namespace detail 

template < class T > 
T trim(T &val) 
{ 
    return detail::trim_impl(val, std::tr1::is_signed<T>()); 
} 

Hãy lưu ý tuy nhiên đó là is_signedfalse_type cho số điểm (đừng hỏi tại sao) nổi. Để làm cho mã trên hoạt động với các điểm nổi, bạn cần phải nhập một đặc điểm khác, ví dụ:

typedef std::tr1::integral_constant< bool, 
      std::tr1::is_signed<T>::value || 
      std::tr1::is_floating_point<T>::value > has_sign; 

... và yeah, sâu sắc hơn bạn nhận được vào Lập trình meta sự xấu xí nó được như vậy ... bỏ qua giải pháp này và đi với một đơn giản được liệt kê bởi Roger: P.

+0

Bạn bỏ lỡ 'phần _impl' và' cái namespace detail' cho hai chức năng đầu tiên. –

+0

Vâng chú ý :), cảm ơn –

+1

Rất tốt lời giải thích và ví dụ cho không gian sử dụng, và không có sự phẫn nộ của tôi trong lịch sử chỉnh sửa quá nghiêm trọng --- Tôi chỉ cần sửa tên của tôi, ngay cả khi tôi làm cho rằng typo đôi khi. * \ * huýt sáo ngây thơ \ **: P –

2

Cờ trình biên dịch để chặn cảnh báo là -Wno-type-limits cho gcc.

+0

Và '-Không-tautological- so sánh' cho Clang ... – jww

1

Tất cả các loại -Wtype-limit cảnh báo có thể bị chặn từng trường hợp bằng cách chuyển đổi từng so sánh, tạo cảnh báo, thành hàm giả, chấp nhận cả toán hạng được sử dụng trong so sánh và trả về kết quả của so sánh toán hạng. Ví dụ, trim() chức năng từ câu hỏi ban đầu có thể được chuyển đổi thành:

// Dummy function for -Wtype-limits warnings suppression. 
template < class T > 
static inline dummy_less(const T &a, const T &b) 
{ 
    return (a < b); 
} 

template < class T > 
T trim(T &val) 
{ 
    if (dumy_less(val, 0)) 
    { 
    val = 0; 
    } 
    return (val); 
} 
+0

Cảm ơn bạn đã cung cấp giải pháp chung. – martinhans

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