2012-11-26 27 views
7

Tôi đã đi qua đoạn mã này là những gì (Tôi đang cố gắng để bao gồm tất cả các chi tiết trong trường hợp tôi đang thiếu một cái gì đó):mục đích typename phân bên trong mẫu

template< typename TYPE = TYPE_with_an_arbitrarily_long_name, 
      typename KIND = KIND_with_an_arbitrarily_long_name> 

class Foo 
{ 
public: 
    virtual void bar(TYPE& t, KIND& k) = 0; 
}; 

Và phần I don' t hiểu là các bài tập bên trong mẫu:

template <typename TYPE = TYPE_with_an_arbitrarily_long_name, .. 

Tôi đã cố gắng hiểu tác dụng của điều này nhưng cho đến nay tôi không thể sản xuất được. Dưới đây là một số nội dung tôi đã cố gắng:

#include <iostream> 
#include <typeinfo> 
using namespace std; 

template<typename T> 
void foo(T t) { 
    cout << typeid(t).name() << " "; 
} 

template<typename T = int> 
void bar(T t) { 
    cout << typeid(t).name() << " "; 
} 

template<typename T = double> 
void baz(T t) { 
    cout << typeid(t).name() << " "; 
} 

int main() 
{ 
    cout << "\nfoo: "; 
    foo(3); foo<int>(3); foo<double>(3); 
    cout << "\nbar: "; 
    bar(3); bar<int>(3); bar<double>(3); 
    cout << "\nbaz: "; 
    baz(3); baz<int>(3); baz<double>(3); 
    return 0; 
} 

in ra:

foo: i i d 
bar: i i d 
baz: i i d 

Vì vậy, câu hỏi của tôi là:

  1. ảnh hưởng của phân bên trong template là gì?
  2. Mục đích của việc sử dụng nó trong ví dụ trên là gì?
  3. Không có câu hỏi thứ ba.

Any help is appreciated ..

EDIT hóa ra chức năng chỉ có thể biên dịch được với C++ 11

Trả lời

7

được gọi là 'mẫu đối số mặc định và quy định cụ thể loại hình được sử dụng, khi không được quy định này - mặc định giống nhau tham số chức năng. Kỹ thuật này được sử dụng rộng rãi cho các lớp học - xem định nghĩa của std::vector hoặc std::string và bạn sẽ thấy chúng có nhiều thông số loại mặc định.

Sử dụng tốt nhất cho tham số kiểu mặc định cho mẫu chức năng là khi đối số kiểu không thể dễ dàng suy luận từ đối số thực, và không được chỉ định rõ ràng - thì trình biên dịch sẽ sử dụng mặc định. Trong ví dụ của bạn, không cần các kiểu mặc định, vì nó có thể dễ dàng được suy ra từ các tham số cuộc gọi thực tế.

Cho đến khi C++ 0x tham số kiểu mặc định chỉ được phép đối với mẫu lớp - chúng không thể sử dụng với mẫu chức năng. Với C++ 0x nó thay đổi, nhưng một số trình biên dịch cũ hơn (ví dụ Visual C++ 2008) sẽ không cho phép bạn sử dụng chúng.

+1

Nitpicking: 'std :: string' không có tham số mẫu nào vì nó là' typedef' (cho 'std :: basic_string '); những gì bạn đang nói về có lẽ là 'std :: basic_string', trong đó có các giá trị mặc định (dựa trên kiểu ký tự) cho các tham số và các tham số cấp phát. –

+0

+1 để làm cho tôi nhận ra tôi đã quên công tắc '-std = C++ 0x' của mình trên – none

7

Đây không phải là nhiệm vụ mà là “giá trị mặc định” cho các đối số loại của mẫu, giống như có một cú pháp tương tự cho các đối số giá trị mặc định của các hàm. Chúng được sử dụng khi một đối số rõ ràng không được chỉ định.

Đối với barbaz mẫu chức năng trong ví dụ của bạn, điều này không có ý nghĩa bởi vì đối với các chức năng này, T sẽ được lấy từ các đối số được chỉ định.

+0

Tôi nghĩ vậy nhưng tại sao 'baz (3)' trả về 'i'? – none

+2

Vì '3' là' int' theo nghĩa đen? –

+0

Như tôi đã nói, đối với 'bar' và' baz', mặc định bạn đã chỉ định không bao giờ được sử dụng. Chúng luôn được khởi tạo theo các kiểu tham số thực tế mà chúng được gọi với, vì vậy lệnh gọi 'baz (3)' thực sự có nghĩa là 'baz (3)'. –

-3

gì bạn đang tìm kiếm là "Mẫu Chuyên ngành"

Dưới đây là một liên kết đến một số Example/Explanation

+0

Chuyên môn mẫu rõ ràng không được tham gia ở đây, chúng chỉ là các tham số mẫu mặc định. –

6

Một hàm template thể không phải là xây dựng tốt nhất để chứng minh lập luận mẫu mặc định. Dưới đây là một cái gì đó tương tự với mẫu-struct:

#include <iostream> 
#include <typeinfo> 

template<typename T = int> 
struct foo { 
    static void f() { 
     std::cout << typeid(T).name() << "\t"; 
    } 
}; 

template<typename T = double> 
struct bar { 
    static void f() { 
     std::cout << typeid(T).name() << "\t"; 
    } 
}; 

int main() { 
    foo<>::f(); foo<int>::f(); foo<double>::f(); std::cout << std::endl; 
    bar<>::f(); bar<int>::f(); bar<double>::f(); std::cout << std::endl; 
} 

Chạy này, tôi nhận được:

% ./a.out 
i i d 
d i d 
+0

vì vậy nó hoạt động cho 'struct' s nhưng không hoạt động? – none

+0

Đối số mẫu mặc định không (theo ý nghĩa) có ý nghĩa với hàm vì kiểu mẫu được ngụ ý bởi kiểu đối số hàm. Với các lớp và cấu trúc, bạn phải xác định rõ ràng loại hoặc sử dụng loại mặc định (nếu được cung cấp). – eduffy

1

Đây là các đối số mẫu mặc định. Bạn có thể sử dụng các đối số mặc định của mẫu để đơn giản hóa việc sử dụng chúng. Ví dụ:

Khi bạn có hai tham số mẫu và đặt loại thông số mẫu cuối cùng làm loại mặc định, bạn phải chỉ định một loại.

std::vector, ví dụ, được định nghĩa là

template < class T, class Allocator = allocator<T> > class vector; 

Ở đây bạn có một mẫu đối số mặc định cho Allocator, vì vậy bạn có thể xác định vectơ chỉ với một đối số

std::vector<int> v; 
2
  1. Các "bài tập "bên trong danh sách tham số mẫu là các tham số mặc định, giống như trong danh sách tham số hàm. Điều đó có nghĩa là trong ví dụ của bạn, Foo<> giống với Foo<TYPE_with_an_arbitrarily_long_name, KIND_with_an_arbitrarily_long_name>Foo<int> giống với Foo<int, KIND_with_an_arbitrarily_long_name>.
  2. Nó sẽ không được sử dụng trong ví dụ của bạn. Bạn hoàn toàn không sử dụng Foo và các tham số của bazbar sẽ luôn được trình biên dịch trích từ các đối số đã cho.
+0

(1) không quan tâm đến' Foo' cho các ví dụ chức năng, chức năng chỉ để trình diễn trong khi 'Foo' là thực tế mã tôi thấy (2) vì vậy khi nào các 'tham số mặc định' bao giờ được sử dụng nếu chúng được suy ra khi tôi không chỉ định bất cứ điều gì và ghi đè khi tôi chỉ định một cái gì đó? – none

+0

Chúng được suy ra _in ví dụ của bạn_ vì các ví dụ của bạn là các hàm. Vì mã bạn thấy trong tự nhiên thực sự là mẫu lớp 'Foo', hãy xem xét' Foo <> 'và' Foo 'mà tôi đã đề cập ở trên làm ví dụ. - hoặc nhìn vào câu trả lời được cung cấp bởi @eduffy –

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