2013-03-24 14 views
13

Tôi đang cố gắng trả lại int64_t nếu std::is_integral<>::value là đúng.Làm cách nào để sử dụng lệnh std :: is_integral <> để chọn triển khai?

Nếu không, tôi muốn gọi to_int64t() trên đối tượng.

Nỗ lực của tôi dưới đây không thành công do không cho phép chuyên môn hóa một phần mẫu chức năng.

#include <type_traits> 
#include <cstdint> 

template<class T,bool is_integral_type> 
int64_t to_int64t(const T& t) 
{ 
     return t; 
} 

template<class T> 
int64_t to_int64t<T,std::is_integral<T>::value>(const T& t) 
{ 
     return t; 
} 

template<class T> 
int64_t to_int64t<T,!std::is_integral<T>::value>(const T& t) 
{ 
     return t.to_int64t(); 
} 

int main() 
{ 
     int64_t i = 64; 
     auto x = to_int64t(i); 
} 
+0

thể trùng lặp: http://stackoverflow.com/questions/12073689/c11-template-function-specialization-for-integer-types – legends2k

Trả lời

28

Chức năng mẫu không thể được một phần chuyên ngành và, nói chung, nó không phải là một ý tưởng tốt để sử dụng chức năng template đặc biệt.

Một cách để đạt được những gì bạn muốn là sử dụng một kỹ thuật gọi là thẻ cử, mà về cơ bản bao gồm trong việc cung cấp một chức năng giao nhận rằng chọn quá tải phù hợp dựa trên giá trị của một cuộc tranh cãi giả thêm:

#include <type_traits> 
#include <cstdint> 

template<class T> 
int64_t to_int64t(const T& t, std::true_type) 
{ 
    return t; 
} 

template<class T> 
int64_t to_int64t(const T& t, std::false_type) 
{ 
    return t.to_int64t(); 
} 

template<class T> 
int64_t to_int64t(const T& t) 
{ 
    return to_int64t(t, std::is_integral<T>()); 
} 

int main() 
{ 
    int64_t i = 64; 
    auto x = to_int64t(i); 
} 

Một khả năng khác là sử dụng kỹ thuật SFINAE cổ điển dựa trên std::enable_if. Đây là cách có thể trông giống (chú ý rằng, vì C++ 11, lập luận mẫu mặc định về chức năng mẫu được phép):

#include <type_traits> 
#include <cstdint> 

template<class T, typename std::enable_if< 
    std::is_integral<T>::value>::type* = nullptr> 
int64_t to_int64t(const T& t) 
{ 
    return t; 
} 

template<class T, typename std::enable_if< 
    !std::is_integral<T>::value>::type* = nullptr> 
int64_t to_int64t(const T& t) 
{ 
    return t.to_int64t(); 
} 

int main() 
{ 
    int64_t i = 64; 
    auto x = to_int64t(i); 
} 

Tuy nhiên, một khả năng khác, mặc dù tiết hơn, là để xác định các mẫu lớp helper (mà có thể một phần chuyên ngành) trong một không gian tên detail và cung cấp một giao toàn cầu - tôi sẽ không sử dụng kỹ thuật này đối với trường hợp sử dụng này, nhưng tôi thấy nó bởi vì nó có thể đến tiện dụng trong những tình huống thiết kế liên quan:

#include <type_traits> 
#include <cstdint> 

namespace detail 
{ 
    template<class T, bool = std::is_integral<T>::value> 
    struct helper { }; 

    template<class T> 
    struct helper<T, true> 
    { 
     static int64_t to_int64t(const T& t) 
     { 
      return t; 
     } 
    }; 

    template<class T> 
    struct helper<T, false> 
    { 
     static int64_t to_int64t(const T& t) 
     { 
      return t.to_int64t(); 
     } 
    }; 
} 

template<class T> 
int64_t to_int64t(const T& t) 
{ 
    return detail::helper<T>::to_int64t(t); 
} 

int main() 
{ 
    int64_t i = 64; 
    auto x = to_int64t(i); 
} 
+0

+1 t y - Tôi sẽ thử cái này – kfmfe04

+0

Ôi trời, cái này thật đẹp. :) – 0x499602D2

+0

@PeteBecker: Cảm ơn bạn đã chỉnh sửa :) –

5

Bạn chỉ có thể sử dụng std::enable_if:

template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0> 
int64_t to_int64t(const T& t) 
{ 
     return t; 
} 

template<class T, typename std::enable_if<!std::is_integral<T>::value, int>::type = 0> 
int64_t to_int64t(const T& t) 
{ 
     return t.to_int64t(); 
}