2015-07-30 29 views
5

Tôi có bộ đếm thời gian biên dịch mà tôi đã sử dụng trong nhiều năm, lấy cảm hứng từ these answers. Nó hoạt động trong C++ 11/3, và như xa như tôi thử nghiệm, tương đối tốt trên các trình biên dịch chính:Bộ đếm thời gian biên dịch trong mẫu lớp

namespace meta 
{ 
    template<unsigned int n> struct Count { char data[n]; }; 
    template<int n> struct ICount : public ICount<n-1> {}; 
    template<> struct ICount<0> {}; 

    #define MAX_COUNT 64 
    #define MAKE_COUNTER(_tag_) \ 
     static ::meta::Count<1> _counter ## _tag_ (::meta::ICount<1>) 
    #define GET_COUNT(_tag_) \ 
     (sizeof(_counter ## _tag_ (::meta::ICount<MAX_COUNT + 1>())) - 1) 
    #define INC_COUNT(_tag_) \ 
     static ::meta::Count<GET_COUNT(_tag_) + 2> _counter ## _tag_ (::meta::ICount<2 + GET_COUNT(_tag_)>) 
} 

Các thử nghiệm compiles and runs perfectly sau (sản lượng dự kiến ​​là 0 1 2 3):

struct Test 
{ 
    MAKE_COUNTER(uu); 

    static const unsigned int a = GET_COUNT(uu); 
    INC_COUNT(uu); 
    static const unsigned int b = GET_COUNT(uu); 
    INC_COUNT(uu); 
    static const unsigned int c = GET_COUNT(uu); 
    INC_COUNT(uu); 
    static const unsigned int d = GET_COUNT(uu); 

}; 

template<typename T> 
void test() 
{ 
    std::cout << T::a << " " << T::b << " " << T::c << " " << T::d << "\n"; 
} 

int main() 
{ 
    test<Test>(); 
} 

Tuy nhiên, Tôi tìm thấy một trường hợp là tôi thấy một hành vi rất lạ xảy ra với clang và gcc. Nếu bạn thay đổi Test thành cấu trúc mẫu, hãy lấy một ví dụ (template<int> struct Testtest<Test<42> >() trong main), clang and gcc both fail to compile, phàn nàn rằng tôi đang xác định lại chức năng bộ đếm (trong khi msvc biên dịch nó mà không gặp sự cố). Đối với một số lý do trình biên dịch không tính toán sizeof trong một lớp mẫu.

clang tìm lỗi ở sốthứ ba, trong khi gcc tìm thấy lỗi thứ hai.

tôi tự mở rộng macro này, và:

  • cho kêu vang, nó mang lại cho

    static ::meta::Count<GET_COUNT(uu)+2> _counteruu(::meta::ICount<(sizeof(_counteruu(::meta::ICount<65>())) - 1)+2>); 
    //               ^          ^
    

    loại bỏ các dấu ngoặc đơn được gạch dưới giải quyết vấn đề này.

  • cho gcc: di chuyển +2 trước sizeof là công việc xung quanh chỉ

Những lưu ý đáng buồn là những cách giải quyết dường như không làm việc khi bao gồm trong macro. Nó giống như trình biên dịch chỉ quên cách tính kết quả của sizeof sau một thời gian ...

Tại sao điều này lại xảy ra? Tôi có làm gì sai, hoặc là nó chỉ là lỗi trình biên dịch (kể từ khi clang và gcc thậm chí không báo cáo cùng một dòng)?

Lưu ý: Tôi biết there is a gcc bug about this counter. Câu hỏi không phải là về lỗi này.

+0

(Bỏ qua tất cả các nhận xét trước đây của tôi, hiện đã bị xóa. Chúng không chính xác. Tôi đã mở rộng một số mẫu theo cách thủ công và không nhớ chính xác những thử nghiệm tôi đã làm.) –

Trả lời

6

Mã của bạn không đúng chuẩn, không cần chẩn đoán. §3.3.7/1, thứ hai điểm đạn :

Một tên N sử dụng trong một lớp S sẽ đề cập đến việc kê khai cùng trong ngữ cảnh của nó và khi đánh giá lại trong phạm vi hoàn thành của S. Không yêu cầu chẩn đoán vì vi phạm quy tắc này.

Bạn sử dụng độ phân giải quá tải để chọn mức quá tải thích hợp của _counteruu. Tuy nhiên, trong trình khởi tạo của ví dụ: a, quá tải (= khai báo) được chọn sẽ không được chọn nếu chúng tôi thực hiện độ phân giải quá tải ở cuối Test, chẳng hạn như trong công cụ khởi tạo d. Do đó _counteruu đề cập đến một tuyên bố khác biệt, khi được đánh giá lại trong phạm vi đã hoàn thành Test.

Để hiển thị lên trong đó kêu gọi chính xác tôi đang đề cập đến, hãy xem xét định nghĩa xử lý trước của Test:

struct Test 
{ 
    // (1) 
    static ::meta::Count<1> _counteruu (::meta::ICount<1>); 
    static const unsigned int a = (sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1); 
    // (2) 
    static ::meta::Count<(sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1) + 2> _counteruu (::meta::ICount<(sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1) + 2>); 
    static const unsigned int b = (sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1); 
    // (3) 
    static ::meta::Count<(sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1) + 2> _counteruu (::meta::ICount<(sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1) + 2>); 
    static const unsigned int c = (sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1); 
    // (4) 
    static ::meta::Count<(sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1) + 2> _counteruu (::meta::ICount<(sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1) + 2>); 
    static const unsigned int d = (sizeof(_counteruu (::meta::ICount<64 + 1>())) - 1); 

}; 

Đơn giản hoá sản lượng

struct Test 
{ 
    // (1) 
    static ::meta::Count<1> _counteruu (::meta::ICount<1>); 
    static const unsigned int a = (sizeof(_counteruu (::meta::ICount<65>())) - 1); 
    // (2) 
    static ::meta::Count<2> _counteruu (::meta::ICount<2>); 
    static const unsigned int b = (sizeof(_counteruu (::meta::ICount<65>())) - 1); 
    // (3) 
    static ::meta::Count<3> _counteruu (::meta::ICount<3>); 
    static const unsigned int c = (sizeof(_counteruu (::meta::ICount<65>())) - 1); 
    // (4) 
    static ::meta::Count<4> _counteruu (::meta::ICount<4>); 
    static const unsigned int d = (sizeof(_counteruu (::meta::ICount<65>())) - 1); 
}; 

Chúng ta có thể thấy rõ cách cơ chế làm việc bây giờ: Quá tải độ phân giải sẽ thích quá tải bổ sung cuối cùng khi ICount<một số lượng đủ lớn> được chuyển do cách chuyển đổi từ gốc sang cơ sở là r bị mắc kẹt. Tuy nhiên, cuộc gọi trong bộ khởi tạo a sẽ chọn quá tải đầu tiên; Nhưng đánh giá lại bộ khởi tạo này sẽ chọn trình khởi tạo cuối cùng.


điểm viên đạn này đã tồn tại trong C++ 03 là tốt, nhưng trong §3.3.6.

+0

Ok, tôi không biết điểm này, vì vậy mã này luôn luôn bị hình thành. Điều thú vị là clang vẫn cho phép một "định nghĩa lại" trước khi ném một lỗi. – Synxis

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