2010-02-17 21 views
24

Tôi chuyên 'ít' (vị ngữ) cho một kiểu dữ liệu.Chuyên môn về 'mẫu <class _Tp> struct std :: less' trong không gian tên khác nhau

Mã này trông như thế này:

template<> 
struct std::less<DateTimeKey> 
{ 
    bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const 
    { 
     // Some code ... 
    } 
} 

Khi biên dịch (g ++ 4.4.1 trên Ubuntu 9.10), tôi nhận được lỗi:

Chuyên ngành 'mẫu struct std :: ít' trong khác nhau namespace

tôi đã làm một số nghiên cứu và phát hiện ra rằng có một 'workaround' có liên quan đến gói các chuyên môn hóa trong một namespace std - tức là thay đổi mã để:

namespace std { 
template<> 
struct less<DateTimeKey> 
{ 
    bool operator()(const DateTimeKey& k1, const DateTimeKey& k2) const 
    { 
     // Some code ... 
    } 
} 
} 

thực sự, tắt trình biên dịch lên. Tuy nhiên, giải pháp đó là từ một bài đăng 5 tuổi (Bởi 'tuyệt vời' Victor Bazarof không ít [chơi đùa ngoài ý muốn]). Đây có phải là sửa chữa vẫn là con đường để đi, hoặc là có một cách tốt hơn để giải quyết này, hoặc là "cách cũ" vẫn còn hợp lệ?

+1

Quá tải toán tử 'DateTimeKey :: kennytm

Trả lời

23

Đây vẫn là cách để thực hiện. Thật không may là bạn không thể khai báo hoặc định nghĩa các hàm trong một không gian tên như bạn sẽ làm với một lớp: bạn cần thực sự bọc chúng trong một khối không gian tên.

+0

Ok, cảm ơn vì đã làm rõ. Tôi sẽ tiếp tục và thực hiện các thay đổi –

3

Ít chức năng không cần phải nằm trong không gian tên std. Vì vậy,

struct A 
{ 
    A(int _v=0):v(_v){} 
    int v; 
}; 


template<> struct less<A> 
{ 
    bool operator()(const A& k1, const A& k2) const 
    { 
     return k1.v < k2.v; 
    } 
}; 


std::map<A,int> m; 
m[A(1)] = 1; 
m[A(2)] = 2; 

Làm việc như mong đợi. (Gọi functor bạn vừa tạo).

Tôi đoán bạn đã biết, nhưng bạn chỉ có thể viết toán tử riêng của mình < (k1, k2), cái mà hàm functor mặc định tìm kiếm.

bool operator<(const DateTimeKey & k1, const DateTimeKey & k2) 
{ 
//your code... 
} 
+3

+1 trên toán tử 'định nghĩa <' thay vì xác định lại ít hơn –

23

Nếu bạn cần chuyên thuật toán chuẩn, bạn có thể làm như vậy trong không gian tên std. Đó là điều duy nhất bạn được phép làm bên trong không gian tên đó theo tiêu chuẩn.

[lib.reserved.names]/1

It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template

Bây giờ, câu hỏi đặt ra là liệu bạn có thực sự muốn chuyên std::less hay không. Lưu ý rằng std::less sẽ gọi toán tử so sánh được xác định cho loại của bạn, do đó bạn có thể cung cấp thao tác đó thay vì chuyên mẫu.

Sự cố với chuyên biệt std::less cho loại cụ thể của bạn là nó sẽ gây nhầm lẫn nếu bạn cung cấp một hoạt động khác với thao tác được thực hiện bởi operator< cho loại của bạn. Nếu họ thực hiện cùng một thao tác, chỉ cần đặt định nghĩa std::less mặc định mà không cần chuyên môn hóa.

Nếu bạn không muốn cung cấp toán tử so sánh, nhưng vẫn muốn sử dụng loại trong vùng chứa kết hợp hoặc với thuật toán yêu cầu so sánh, bạn có thể cung cấp hàm so sánh bên ngoài bằng tên khác sẽ không gây nhầm lẫn cho người đọc khác và bản thân bạn ở đâu đó trong tương lai).

+0

+1 cho báo giá và trả lời câu hỏi cũng như đưa ra giải pháp thay thế tốt. – JonM

3

Tại sao bạn thậm chí làm điều này?

std::less tồn tại cho chỉ có hai mục đích:

  1. để đặt tên cho hành <, cho phép nó được thông qua như là một functor
  2. đến một cách rõ ràng cho phép so sánh hai con trỏ mà không phải là trong cùng một mảng (về mặt kỹ thuật là bất hợp pháp nếu được thực hiện với con trỏ thô)

Không có lý do gì để người dùng quá tải - quá tải operator< hoặc sử dụng chức năng so sánh tùy chỉnh.

Có các thuật toán std có thể được sử dụng một cách hợp lý - std::swap là một ví dụ hay - và để làm như vậy bạn cần khai báo chuyên môn bên trong không gian tên std.

+2

Tôi không chắc chắn std :: swap là một ví dụ tốt, vì tiền thông minh là bạn không chuyên nó, bạn định nghĩa một hàm 'swap' độc lập trong cùng một không gian tên như UDT, và để ADL tìm thấy nó. Ngoại lệ tôi có thể nghĩ là nếu lớp của bạn phải làm việc với một khuôn mẫu không bao giờ có bản ghi nhớ đó, và nó gọi 'std :: swap (t1, t2)' thay vì 'using std :: swap; hoán đổi (t1, t2); '. Không chắc chắn cho dù đây là chuyên môn hợp lý, hoặc chỉ chuyên môn thực dụng ;-) –

+0

Đã có nhiều cuộc thảo luận về danh sách gửi thư tốt nhất về điều đó là tốt nhất, đó là lý do tại sao tăng :: trao đổi chọn lên. –

+1

'std :: less' tồn tại vì lý do thứ ba: Đôi khi, toán tử' của một loại 'hoạt động hơi lạ. Ví dụ chính là các số dấu phẩy động mà người ta có thể muốn đối xử với '-0.0' khác với' 0.0', hoặc nơi người ta có thể muốn làm cho 'nan' có thể so sánh được. Các ví dụ khác là các kiểu chỉ có một phần trật tự, và trong đó ký hiệu '<' là một ký hiệu tên miền tự nhiên cụ thể. Trong những trường hợp này, chuyên 'std :: less' cho phép sử dụng loại này trong bộ và bản đồ. –

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