2012-08-22 28 views
22

Giả sử tôi có một hàm template:C++ 11: Template Function Chuyên cho Integer loại

template<typename T> 
void f(T t) 
{ 
    ... 
} 

và tôi muốn viết một chuyên môn hóa cho tất cả các loại nguyên nguyên thủy. Cách tốt nhất để làm việc này là gì?

Những gì tôi có nghĩa là:

template<typename I where is_integral<I>::value is true> 
void f(I i) 
{ 
    ... 
} 

và trình biên dịch chọn phiên bản thứ hai với nhiều loại nguyên, và phiên bản đầu tiên cho tất cả mọi thứ khác?

+0

Có chuyên môn mẫu cho các chức năng trong C++ 11 không? Tôi nghĩ trong C++ 03 nó chỉ là quá tải. –

+0

Tôi đã tìm kiếm một cái gì đó tương tự, nhưng không thành công. tất cả những gì tôi có thể làm chỉ là xác định một mẫu bình thường, và bên trong tôi kiểm tra nếu tham số đã cho là kiểu số nguyên –

+3

@AlexanderChertov có trong C++ 03, nhưng [nó phức tạp] (http://www.gotw.ca /publications/mill17.htm). Điều tương tự áp dụng cho C++ 11. – juanchopanza

Trả lời

36

Sử dụng SFINAE

// For all types except integral types: 
template<typename T> 
typename std::enable_if<!std::is_integral<T>::value>::type f(T t) 
{ 
    // ... 
} 

// For integral types only: 
template<typename T> 
typename std::enable_if<std::is_integral<T>::value>::type f(T t) 
{ 
    // ... 
} 

Lưu ý rằng bạn sẽ phải bao gồm đầy đủ các std::enable_if giá trị trả về ngay cả đối với khai báo.

+1

Bạn đã thay đổi giá trị trả lại của hàm từ void thành một thứ khác. Điều gì xảy ra nếu hàm ban đầu trả về một kiểu? Ví dụ một lớp X? 'mẫu X f (T t)'? Làm thế nào nó sẽ xem xét sau đó? –

+0

@ AndrewTomazos-Fathomling, 'std :: ebable_if :: type' bị vô hiệu, nếu chỉ cho một tham số mẫu; hoặc tham số mẫu thứ 2. – Lol4t0

+1

@ AndrewTomazos-Fathomling Đối số mẫu thứ hai của 'std :: enable_if' được mặc định là' void'. Đó là kiểu trả về của bạn. Tôi để nó mặc định, nhưng bạn có thể thay đổi nó thành bất kỳ kiểu trả về nào bạn muốn. Bạn thậm chí có thể có các kiểu tích phân trả về một kiểu khác với kiểu không tách rời. – David

11

dùng C++ 11, std :: enable_if (http://en.cppreference.com/w/cpp/types/enable_if) có thể được sử dụng để làm điều đó:

template<typename T, class = typename std::enable_if<std::is_integral<T>::value>::type> 
void f(T t) {...} 
+0

Mã đó có hợp lệ không? – Andrey

+1

Hầu như, nhưng anh đã làm sai. – David

+0

edited :) cú pháp khá phức tạp! – arnoo

7

Bạn có thể sử dụng một mẫu helper mà bạn có thể chuyên như thế này:

#include <string> 
#include <iostream> 
#include <type_traits> 

template <typename T, bool = std::is_integral<T>::value> 
struct Foo { 
     static void bar(const T& t) { std::cout << "generic: " << t << "\n"; } 
}; 
template <typename T> 
struct Foo<T, true> { 
     static void bar(const T& t) { std::cout << "integral: " << t << "\n"; } 
}; 

template <typename T> 
static void bar(const T& t) { 
     return Foo<T>::bar(t); 
} 

int main() { 
     std::string s = "string"; 
     bar(s); 
     int i = 42; 
     bar(i); 
     return 0; 
} 

đầu ra:

generic: string 
integral: 42 
+1

+1 cho ủy nhiệm mẫu lớp, vì điều này cho phép không chỉ rõ ràng mà còn một phần Điều này cũng phù hợp với Tiêu chuẩn mã hóa Sutter & Alexandrescu 'Item 66: "không chuyên mẫu chức năng." – TemplateRex

+0

@rhalbersma Tôi thích câu trả lời này, nhưng tôi không nghĩ rằng lý do của bạn là âm thanh. Nó đơn giản không phải là một lựa chọn thực tế để sử dụng chức năng chuyên môn hóa mẫu cho vấn đề này – David

+0

Bản thân câu hỏi được yêu cầu cho "chuyên môn hóa" – mitchnull

19

Tôi sẽ sử dụng độ phân giải quá tải. Điều đó sẽ khiến bạn không phải sử dụng toàn bộ SFINAE hack. Thật không may có rất nhiều lĩnh vực mà bạn không thể tránh được nó, nhưng may mắn thay không phải là một trong số đó.

template<typename T> 
void f(T t) 
{ 
    f(t, std::is_integral<T>()); 
} 

template<typename T> 
void f(T t, std::true_type) 
{ 
    // ... 
} 

template<typename T> 
void f(T t, std::false_type) 
{ 
    // ... 
} 
Các vấn đề liên quan