2011-07-08 17 views
7
template<typename T> 
struct A 
{ 
    A<T> operator%(const T& x); 
}; 

template<typename T> 
A<T> A<T>::operator%(const T& x) { ... } 

Tôi làm cách nào để sử dụng enable_if để thực hiện chuyên môn sau cho bất kỳ loại dấu phẩy động nào (is_floating_point)?enable_if phương pháp chuyên môn hóa

template<> 
A<float> A<float>::operator%(const float& x) { ... } 

EDIT: Dưới đây là một câu trả lời tôi đã đưa ra đó là khác biệt so với những người đăng tải dưới đây ...

template<typename T> 
struct A 
{ 
    T x; 

    A(const T& _x) : x(_x) {} 

    template<typename Q> 
    typename std::enable_if<std::is_same<Q, T>::value && std::is_floating_point<Q>::value, A<T> >::type operator% (const Q& right) const 
    { 
     return A<T>(fmod(x, right)); 
    } 

    template<typename Q> 
    typename std::enable_if<std::is_convertible<Q, T>::value && !std::is_floating_point<Q>::value, A<T> >::type operator% (const Q& right) const 
    { 
     return A<T>(x%right); 
    } 
}; 

Giống như các áp phích bên dưới nói, sử dụng enable_if có thể không lý tưởng cho vấn đề này (rất khó đọc)

Trả lời

25

Sử dụng quá tải thay vì chuyên môn rõ ràng khi bạn muốn tinh chỉnh hành vi cho loại thông số cụ thể hơn. Nó dễ dàng hơn để sử dụng (bất ngờ ít hơn) và mạnh hơn

template<typename T> 
struct A 
{ 
    A<T> operator%(const T& x) { 
     return opModIml(x, std::is_floating_point<T>()); 
    } 

    A<T> opModImpl(T const& x, std::false_type) { /* ... */ } 
    A<T> opModImpl(T const& x, std::true_type) { /* ... */ } 
}; 

Một ví dụ sử dụng SFINAE (enable_if) như bạn dường như tò mò

template<typename T> 
struct A 
{ 
    A<T> operator%(const T& x) { 
     return opModIml(x); 
    } 

    template<typename U, 
      typename = typename 
       std::enable_if<!std::is_floating_point<U>::value>::type> 
    A<T> opModImpl(U const& x) { /* ... */ } 

    template<typename U, 
      typename = typename 
       std::enable_if<std::is_floating_point<U>::value>::type> 
    A<T> opModImpl(U const& x) { /* ... */ } 
}; 

Way xấu xí dĩ nhiên hơn. Không có lý do gì để sử dụng enable_if ở đây, tôi nghĩ vậy. Đó là quá mức cần thiết.

+0

Tôi đánh giá cao câu trả lời và tôi làm như giải pháp của bạn, nhưng tôi không đồng ý với lý do tại sao bạn nghĩ rằng mẫu chuyên môn là sai. Nếu có thể chuyên dùng cho nhiều loại bằng cách sử dụng enable_if, tôi vẫn muốn biết cách – David

+0

@Dave vì bạn có thể sử dụng quá tải thay thế. Trường hợp bạn có một tham số và bạn muốn chuyên cho các kiểu tham số, quá tải sẽ tốt hơn. Không, bạn không thể "chuyên với' enable_if' ". Những gì bạn có nghĩa là quá tải. Tôi sẽ thêm một ví dụ rằng quá tải và sử dụng SFINAE. –

+0

Điều này nghe có vẻ ngu ngốc nhưng tôi không thích opModImpl ở đó, ngay cả khi đó là riêng tư. Ngoài ra tôi không thích ý tưởng về khả năng có thêm tạm thời được tạo ở đó, mặc dù trình tối ưu hóa sẽ loại bỏ nó. C++ 0x nên chỉ bao gồm một cách để có nhiều chuyên ngành sử dụng cùng một định nghĩa ở địa điểm đầu tiên – David

2

Bạn cũng có thể sử dụng một mẫu tham số boolean mặc định như thế này:

template<typename T> 
struct A 
{ 
    T x; 

    A(const T& _x) : x(_x) {} 

    template<bool EnableBool = true> 
    typename std::enable_if<std::is_floating_point<T>::value && EnableBool, A<T> >::type 
    operator% (const T& right) const 
    { 
     return A<T>(fmod(x, right)); 
    } 

    template<bool EnableBool = true> 
    typename std::enable_if<!std::is_floating_point<T>::value && EnableBool, A<T> >::type 
    operator% (const T& right) const 
    { 
     return A<T>(x%right); 
    } 
};