2010-03-15 36 views
173

Tại sao đối số mẫu mặc định chỉ được phép trên mẫu lớp? Tại sao chúng ta không thể định nghĩa một kiểu mặc định trong một mẫu hàm thành viên? Ví dụ:Đối số mẫu mặc định cho mẫu chức năng

struct mycclass { 
    template<class T=int> 
    void mymember(T* vec) { 
    // ... 
    } 
}; 

Thay vào đó, C++ buộc đối số mẫu mặc định chỉ được phép trên mẫu lớp.

+8

+1 Đó thực sự là một câu hỏi phức tạp. – AraK

+1

Đối với ba câu trả lời đầu tiên được đăng, hãy xem xét ví dụ này: 'struct S {template R get_me_R() {\t return R(); }}; 'Tham số mẫu không thể được suy ra từ ngữ cảnh. – AraK

+3

Câu hỏi hay. 3 người đã trả lời để nói rằng "không có ý nghĩa", và tất cả đều sai lầm nói chung. Các tham số mẫu chức năng là * không * luôn được khấu trừ từ các tham số gọi hàm. Ví dụ, nếu chúng được cho phép tôi có thể viết 'mẫu int & increment (int & i) {i + = N; trả lại i; } ', và sau đó' increment (i); 'hoặc' increment <2> (i); '. Vì nó là, tôi phải viết 'increment <1> (i);'. –

Trả lời

138

Có ý nghĩa khi đưa ra các đối số mẫu mặc định. Ví dụ: bạn có thể tạo chức năng sắp xếp:

template<typename Iterator, 
     typename Comp = std::less< 
      typename std::iterator_traits<Iterator>::value_type> > 
void sort(Iterator beg, Iterator end, Comp c = Comp()) { 
    ... 
} 

C++ 0x giới thiệu chúng với C++. Xem báo cáo lỗi này bởi Bjarne Stroustrup: Default Template Arguments for Function Templates và những gì ông nói

The prohibition of default template arguments for function templates is a misbegotten remnant of the time where freestanding functions were treated as second class citizens and required all template arguments to be deduced from the function arguments rather than specified.

The restriction seriously cramps programming style by unnecessarily making freestanding functions different from member functions, thus making it harder to write STL-style code.

+0

Có một số liên kết với thông tin đó không? – Arman

+0

@Arman, liên kết báo cáo lỗi có chứa các thay đổi được thực hiện đối với bản nháp làm việc cho C++ 0x và các cuộc thảo luận. Các đối số không suy luận cũng như không được chỉ định rõ ràng được lấy từ các đối số mặc định. GCC4.4 hỗ trợ các đối số mặc định cho các mẫu hàm trong chế độ C++ 0x. –

+4

Không có gì để làm với câu hỏi hoặc câu trả lời, nhưng Herb Sutter gọi tiêu chuẩn upcomming C++ 11 sau cuộc họp thứ bảy vừa qua. Tôi chỉ đọc nó ngày hôm nay và cảm thấy như chia sẻ :) http://herbsutter.wordpress.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/ –

33

Để báo C++ Templates: The Complete Guide (trang 207):

When templates were originally added to the C++ language, explicit function template arguments were not a valid construct. Function template arguments always had to be deducible from the call expression. As a result, there seemed to be no compelling reason to allow default function template arguments because the default would always be overridden by the deduced value.

+0

đơn giản và ngắn gọn :) – InQusitive

16

Cho đến nay, tất cả các ví dụ chìa của các tham số mẫu mặc định cho các mẫu chức năng có thể được thực hiện với quá tải.

Arak:

struct S { 
    template <class R = int> R get_me_R() { return R(); } 
}; 

có thể là:

struct S { 
    template <class R> R get_me_R() { return R(); } 
    int get_me_R() { return int(); } 
}; 

My own:

template <int N = 1> int &increment(int &i) { i += N; return i; } 

có thể là:

template <int N> int &increment(int &i) { i += N; return i; } 
int &increment(int &i) { return increment<1>(i); } 

litb:

template<typename Iterator, typename Comp = std::less<Iterator> > 
void sort(Iterator beg, Iterator end, Comp c = Comp()) 

có thể là:

template<typename Iterator> 
void sort(Iterator beg, Iterator end, std::less<Iterator> c = std::less<Iterator>()) 

template<typename Iterator, typename Comp > 
void sort(Iterator beg, Iterator end, Comp c = Comp()) 

Stroustrup:

template <class T, class U = double> 
void f(T t = 0, U u = 0); 

thể là:

template <typename S, typename T> void f(S s = 0, T t = 0); 
template <typename S> void f(S s = 0, double t = 0); 

Mà tôi chứng minh với đoạn mã sau:

#include <iostream> 
#include <string> 
#include <sstream> 
#include <ctype.h> 

template <typename T> T prettify(T t) { return t; } 
std::string prettify(char c) { 
    std::stringstream ss; 
    if (isprint((unsigned char)c)) { 
     ss << "'" << c << "'"; 
    } else { 
     ss << (int)c; 
    } 
    return ss.str(); 
} 

template <typename S, typename T> void g(S s, T t){ 
    std::cout << "f<" << typeid(S).name() << "," << typeid(T).name() 
     << ">(" << s << "," << prettify(t) << ")\n"; 
} 


template <typename S, typename T> void f(S s = 0, T t = 0){ 
    g<S,T>(s,t); 
} 

template <typename S> void f(S s = 0, double t = 0) { 
    g<S,double>(s, t); 
} 

int main() { 
     f(1, 'c');   // f<int,char>(1,'c') 
     f(1);    // f<int,double>(1,0) 
//  f();    // error: T cannot be deduced 
     f<int>();   // f<int,double>(0,0) 
     f<int,char>();  // f<int,char>(0,0) 
} 

Đầu ra in khớp với nhận xét cho mỗi cuộc gọi đến f và cuộc gọi nhận xét không thể biên dịch như mong đợi.

Vì vậy, tôi nghi ngờ rằng các tham số mẫu mặc định "là không cần thiết", nhưng có lẽ chỉ trong cùng một nghĩa là các đối số mặc định của hàm "không cần thiết". Theo báo cáo lỗi của Stroustrup, việc bổ sung các tham số không được suy luận đã quá muộn để mọi người có thể nhận ra và/hoặc thực sự đánh giá cao rằng nó đã làm cho các giá trị mặc định có ích. Vì vậy, tình hình hiện tại là có hiệu lực dựa trên một phiên bản của các mẫu chức năng mà không bao giờ là tiêu chuẩn.

+0

@Steve: Vì vậy, trứng đã chạy nhanh hơn gà? :) thú vị. Cảm ơn. – Arman

+1

Có lẽ chỉ là một trong những điều đó. Quá trình chuẩn hóa C++ chạy chậm một phần để mọi người có thời gian nhận ra khi một thay đổi tạo ra các cơ hội hoặc khó khăn ở nơi khác trong tiêu chuẩn. Những khó khăn hy vọng bị bắt bởi những người thực hiện dự thảo tiêu chuẩn khi họ đi cùng, khi họ phát hiện một mâu thuẫn hoặc mơ hồ. Cơ hội để cho phép những thứ không được phép trước, dựa vào ai đó muốn viết mã thông báo rằng nó không còn cần phải là bất hợp pháp nữa ... –

+2

Một điều nữa cho bạn: 'template int SomeFunction() ; '. Tham số mẫu ở đây không bao giờ được sử dụng và trên thực tế, hàm này không bao giờ được gọi; nơi duy nhất nó được gọi là trong một 'decltype' hoặc' sizeof'. Tên cố tình khớp với tên của một hàm khác nhưng thực tế đó là một khuôn mẫu có nghĩa là trình biên dịch sẽ thích hàm miễn phí nếu nó tồn tại. Cả hai được sử dụng trong SFINAE để cung cấp hành vi mặc định khi thiếu định nghĩa hàm. – Tom

1

Những gì tôi sử dụng là lừa tiếp theo:

phép nói rằng bạn muốn có chức năng như thế này:

template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array) 
{ 
    E one(1); 
    array.add(one); 
} 

Bạn sẽ không được phép, nhưng tôi làm theo cách sau:

template <typename T> 
struct MyArray_t { 
void add(T i) 
{ 
    // ... 
} 
}; 

template <typename E, typename ARR_E = MyArray_t<E> > 
class worker { 
public: 
    /*static - as you wish */ ARR_E* parr_; 
    void doStuff(); /* do not make this one static also, MSVC complains */ 
}; 

template <typename E, typename ARR_E> 
void worker<E, ARR_E>::doStuff() 
{ 
    E one(1); 
    parr_->add(one); 
} 

Vì vậy, theo cách này, bạn có thể sử dụng nó như sau:

MyArray_t<int> my_array; 
worker<int> w; 
w.parr_ = &arr; 
w.doStuff(); 

Như chúng ta có thể thấy không cần phải thiết lập một cách rõ ràng tham số thứ hai. Có thể nó sẽ hữu ích cho ai đó.

+0

Đây chắc chắn không phải là câu trả lời. – Puppy

+0

@deadmg - bạn có thể giải thích tại sao không? Chúng tôi không phải tất cả các chuyên gia mẫu C++. Cảm ơn. – Kev

+0

Đây là một giải pháp khá gọn gàng nhưng nó sẽ không bao gồm tất cả các trường hợp bạn có thể muốn. Ví dụ như thế nào bạn sẽ áp dụng điều này cho một nhà xây dựng? –

4

Trên Windows, với tất cả các phiên bản của Visual Studio, bạn có thể chuyển đổi lỗi này (C4519) để cảnh cáo hoặc vô hiệu hóa nó như vậy:

#ifdef _MSC_VER 
#pragma warning(1 : 4519) // convert error C4519 to warning 
// #pragma warning(disable : 4519) // disable error C4519 
#endif 

Xem thêm chi tiết here.

+1

Lưu ý rằng, trong khi điều này làm vô hiệu hóa các đối số "mẫu mặc định chỉ được phép trên một mẫu lớp", nó không thực sự làm cho quá trình tạo bản mẫu * sử dụng * giá trị được cung cấp. Điều đó đòi hỏi VS2013 (hoặc bất kỳ trình biên dịch nào khác đã hoàn thành lỗi C++ 11 226 "Đối số mẫu mặc định cho các mẫu hàm") – puetzk

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