2016-11-01 20 views
26

Trong C++ 11, Tôi đang sử dụng nàyC++ 11 - typeid độc đáo

typeid(T).name() 

cho tính toán hash của riêng tôi. Tôi không cần kết quả giống nhau giữa chương trình chạy hoặc biên dịch. Tôi chỉ cần nó là duy nhất cho các loại. Tôi biết, nó có thể trả về cùng tên cho các loại khác nhau, nhưng thường là với const, con trỏ, v.v. Trong trường hợp của tôi, T chỉ là class XY, struct XX hoặc các loại có nguồn gốc.

Trong trường hợp này, tôi có thể giả định rằng T sẽ là duy nhất không?

+0

liên quan: http://stackoverflow.com/questions/28861760/what-is-the-actual-purpose-of-stdtype-infoname –

+0

Người duy nhất có thể đảm bảo rằng 'T' là duy nhất là bạn . Bạn có chắc là bạn đã hỏi đúng câu hỏi? –

Trả lời

25

Bạn nên sử dụng std::type_index cho mục đích lập bản đồ.

Lớp type_index là một lớp bao bọc xung quanh một std :: type_info đối tượng, có thể được sử dụng như chỉ mục trong kết hợp và có thứ tự container kết hợp. Mối quan hệ với đối tượng type_info là được duy trì thông qua một con trỏ, do đó type_index là CopyConstructible và CopyAssignable.

+0

Và 'type_index' có an toàn theo cách này không? Ví dụ. có wont được cùng 'loại_index' cho các loại khác nhau? –

+1

@MartinPerry xem xét tiêu chuẩn, không có sự khẳng định chắc chắn về tính độc đáo, nhưng có một số manh mối trong 5.2.8. Ngoài ra, Stroustrup tự đề xuất việc sử dụng địa chỉ của typeid (tức là đối tượng type_info) để mở rộng hệ thống typeinfo, cũng giả định tính duy nhất. – Christophe

+3

@MartinPerry, việc triển khai tuân thủ có thể không làm gì hơn là chuyển tiếp đến điểm tham chiếu 'std :: type_info'. Tuy nhiên, việc sử dụng 'type_index' sẽ xử lý các minutiae liên quan đến việc tạo ra' type_info' một khóa hợp lệ. * Sau đó *, nếu bạn thấy mặc định 'std :: hash' hoạt động theo kiểu tối ưu phụ, bạn có thể tạo một loại' Hasher' tùy chỉnh (hoặc thay thế kiểu hiện tại của bạn từ khi bắt đầu). – StoryTeller

19

std::type_info::name được xác định thực hiện, do đó bạn không nên dựa vào đó là duy nhất cho các loại khác nhau.

Vì bạn đang thực hiện việc này để tính toán băm, bạn nên sử dụng std::type_info::hash_code để thay thế. Mặc dù điều này không bảo đảm rằng các giá trị sẽ là duy nhất, tiêu chuẩn cho biết rằng việc triển khai nên thử và trả về các giá trị khác nhau cho các loại khác nhau. Miễn là việc triển khai bản đồ băm của bạn có xử lý va chạm hợp lý, điều này sẽ đủ cho bạn.

+5

'std :: type_info :: hash_code' không được đảm bảo là duy nhất trên nhiều loại! – themagicalyang

+0

@themagicalyang Thật sao? Tiêu chuẩn cho biết "triển khai sẽ trả về các giá trị khác nhau cho hai đối tượng type_info không phải là so sánh bằng nhau". – TartanLlama

+0

Tôi không kiểm tra dự thảo, nhưng cppreference nói "Trả về một giá trị không xác định, giống hệt với các đối tượng type_info tham chiếu đến cùng một loại. Không được bảo đảm khác. Ví dụ, cùng một giá trị có thể được trả về cho các giá trị khác nhau Các giá trị cũng có thể thay đổi giữa các lời gọi của cùng một chương trình " – themagicalyang

5

Như đã nêu trên cppreference:

Trả về thực hiện quy định null-chấm dứt chuỗi ký tự chứa tên của các loại. Không có đảm bảo nào được cung cấp, cụ thể là, trong trường hợp đặc biệt là , chuỗi trả lại có thể giống hệt nhau đối với một số loại và thay đổi giữa các lời gọi của cùng một chương trình.

Vì vậy, không, bạn không thể. Bạn không thể giả định bất cứ điều gì thực sự.

Mặc dù, hash_code() mang đến cho bạn:

size_t hash_code() const noexcept;

7 Returns: Một giá trị không xác định, ngoại trừ trong một thực đơn của chương trình, nó sẽ trả về giá trị tương tự cho bất kỳ hai type_info các đối tượng so sánh bằng nhau.

8 Ghi chú: việc triển khai sẽ trả về các giá trị khác nhau cho hai đối tượng type type_info không so sánh bằng.

Có nghĩa là hash_code() chỉ có thể được sử dụng để phân biệt hai loại khác nhau nếu operator== cho type_info hỗ trợ điều này.

2

Điều bạn có thể làm là lấy địa chỉ của thành viên.

class HashBase { 
    virtual intptr_t get() = 0; 
}; 

template <typename T> 
class Hash : HashBase { 
    static const int _addr = 0; 
    intptr_t get() override { return reinterpret_cast<intptr_t>(&_addr); } 
};