Mã của bạn không hoạt động vì bộ tiền xử lý, chịu trách nhiệm tìm kiếm và mở rộng các macro bạn sử dụng trong mã của mình, không biết chính ngôn ngữ đó. Nó chỉ là một trình phân tích cú pháp văn bản. Nó thấy rằng STRINGIFY (T) trong khuôn mẫu hàm rất và mở rộng nó, nhiều trước khi bạn đưa ra một kiểu cho khuôn mẫu đó. Khi nó quay ra, bạn sẽ luôn luôn nhận được "T" thay vì typename bạn mong đợi, không may.
Như litb đề nghị, tôi đã (nặng) thực hiện này `getTypeName' hàm mẫu trả về typename bạn vượt qua nó:
#include <iostream>
template <typename _Get_TypeName>
const std::string &getTypeName()
{
static std::string name;
if (name.empty())
{
const char *beginStr = "_Get_TypeName =";
const size_t beginStrLen = 15; // Yes, I know...
// But isn't it better than strlen()?
size_t begin,length;
name = __PRETTY_FUNCTION__;
begin = name.find(beginStr) + beginStrLen + 1;
length = name.find("]",begin) - begin;
name = name.substr(begin,length);
}
return name;
}
int main()
{
typedef void (*T)(int,int);
// Using getTypeName()
std::cout << getTypeName<float>() << '\n';
std::cout << getTypeName<T>() << '\n'; // You don't actually need the
// typedef in this case, but
// for it to work with the
// typeid below, you'll need it
// Using typeid().name()
std::cout << typeid(float).name() << '\n';
std::cout << typeid(T).name() << '\n';
return 0;
}
Đoạn mã trên kết quả ở đầu ra sau đây với -s GCC cờ ("dải tất cả các biểu tượng từ nhị phân") được kích hoạt:
float
void (*)(int, int)
f
PFviiE
Vì vậy, bạn sẽ thấy, getTypename() làm một công việc khá tốt, với chi phí mà fugly chuỗi phân tích cú pháp Hack (tôi biết, đó là chết tiệt xấu xí).
Một vài điểm để đưa vào tài khoản:
- Mã này chỉ là GCC. Tôi không biết làm thế nào để chuyển nó sang trình biên dịch khác. Có lẽ chỉ có một vài người khác có một cơ sở như vậy để sản xuất tên chức năng khá đẹp, và từ những gì tôi tìm kiếm, MSVC++ không có một, nếu bạn đang tự hỏi mình điều đó.
- Nếu, trong một phiên bản mới, GCC định dạng
__PRETTY_FUNCTION__
của một cách khác nhau, kết hợp chuỗi có thể phá vỡ và bạn sẽ phải sửa chữa nó. Vì lý do này tôi cũng cảnh báo rằng getTypeName() có thể là tốt để gỡ lỗi (và, vẫn có thể không tốt cho điều đó), nhưng nó là chắc chắn xấu, xấu và xấu cho các mục đích khác như so sánh hai loại trong một mẫu hoặc một cái gì đó như thế (tôi không biết, chỉ đoán những gì ai đó có thể nghĩ đến ..). Sử dụng nó chỉ để gỡ lỗi, và ưu tiên không gọi nó trong bản phát hành bản phát hành (sử dụng macro để vô hiệu hóa), do đó bạn không sử dụng __PRETTY_FUNCTION__
và do đó trình biên dịch không tạo chuỗi cho nó.
- Tôi chắc chắn không có chuyên gia, và tôi không chắc chắn liệu một số loại lẻ có thể gây ra chuỗi phù hợp với thất bại. Tôi muốn hỏi những người đọc bài này để bình luận nếu họ biết về một trường hợp như vậy.
- Mã sử dụng chuỗi tĩnh std ::. Nó có nghĩa là, nếu một số ngoại lệ được ném từ constructor hoặc destructor của nó, không có cách nào mà nó sẽ đạt đến một khối catch và bạn sẽ nhận được một ngoại lệ unhandled. Tôi không biết liệu std :: strings có thể làm điều đó, nhưng hãy cẩn thận rằng, nếu họ làm, bạn có khả năng gặp rắc rối. Tôi sử dụng nó bởi vì nó cần một destructor để giải phóng bộ nhớ. Bạn có thể thực hiện lớp của riêng bạn cho rằng, mặc dù, đảm bảo không có ngoại lệ được ném ngoài thất bại phân bổ (đó là khá nhiều chết người, phải không? Vì vậy ...), và trả về một chuỗi C đơn giản.
- Với typedefs bạn có thể nhận được một số kết quả kỳ lạ, như thế này (đối với một số lý do, trang web phá vỡ định dạng của đoạn này, vì vậy tôi đang sử dụng dán liên kết này): http://pastebin.com/f51b888ad
Mặc dù những nhược điểm, tôi Tôi muốn nói rằng nó chắc chắn là nhanh chóng. Lần thứ hai bạn tra cứu cho cùng một tên kiểu, nó sẽ tốn chi phí khi chọn một tham chiếu đến một chuỗi std toàn cầu :: chứa tên. Và, tương đối so với các phương pháp mẫu đặc biệt được đề xuất trước đây, không có gì khác bạn phải khai báo bên cạnh chính khuôn mẫu đó, vì vậy nó thực sự dễ sử dụng hơn nhiều.
Độ phân giải mẫu sẽ khởi động trong * dài * sau khi bộ xử lý trước thực hiện công việc của nó. Dù sao, các mẫu được nhiều hơn thay thế văn bản (tốt, nó thậm chí không thay thế văn bản), do đó, thay đổi thứ tự của các hoạt động nó sẽ không giải quyết vấn đề của bạn. –
Bộ tiền xử lý khởi động trước khá nhiều * mọi thứ *. Do đó tên ** trước ** - bộ vi xử lý. –
Tôi đã thấy mọi người làm 'template char const * get_type_name() {return __PRETTY_FUNCTION__; } 'và sau đó giải nén' T = ... 'ra khỏi chuỗi. –