2011-09-06 55 views
40

Khi thực hiện lập trình meta bằng cách sử dụng mẫu C++, có phương pháp nào có thể được sử dụng, sắp xếp giống như trình gỡ rối, để hướng dẫn cách các mẫu được khởi tạo và tuân thủ không? Có vẻ như ngay bây giờ, khi tạo một mạng lưới các mẫu phức tạp, thực sự không phải là một cách hay để gỡ lỗi chúng ngoài việc xem các thông báo lỗi của trình soạn thảo để xem các mẫu đang được khởi tạo như thế nào (nếu có bất kỳ lỗi trình biên dịch nào), và nỗ lực làm việc ngược từ các thông báo lỗi nếu có điều gì đó không mong muốn được tạo ra. Tôi không thực sự chắc chắn nếu những gì tôi đang tìm kiếm thậm chí tồn tại, vì nó sẽ có được một cái gì đó được thực hiện tại thời gian biên dịch, nhưng về cơ bản nó sẽ là một phương pháp, loại giống như bước qua mã và kiểm tra khung stack trong gdb khi chạy, nơi trình biên dịch có thể được dừng lại và môi trường được kiểm tra cho chuỗi theo đó một mẫu hoặc tập hợp các mẫu lồng nhau đang được khởi tạo.Gỡ lỗi mẫu ngay lập tức

Ví dụ, giả sử tôi tạo ra một số mã đơn giản như sau:

template<typename T, typename R = void> 
struct int_return_type {}; 

template<typename R> 
struct int_return_type<int, R> 
{ 
    typedef R type; 
}; 

template<typename T, typename R = void> 
struct float_return_type {}; 

template<typename R> 
struct float_return_type<float, R> 
{ 
    typedef R type; 
}; 

template<typename T> 
typename int_return_type<T>::type test() 
{ 
    cout << "T type is int" << endl; 
} 

template<typename T> 
typename float_return_type<T>::type test() 
{ 
    cout << "T type is float" << endl; 
} 

int main() 
{ 
    test<int>(); 
    test<float>(); 
    return 0; 
} 

Tôi biết điều này là mã tương đối dễ dàng để làm theo, nhưng các mẫu có thể tham gia khá hơn một chút, đặc biệt là khi làm lập trình meta, đệ quy, vv Tôi hiểu rằng trình biên dịch sẽ phát hành các thông báo lỗi có thể được sử dụng để suy ra cách các mẫu được khởi tạo, nhưng tôi cũng tự hỏi điều gì có thể được thực hiện khi mã mẫu thực tế đúng theo nghĩa cú pháp, nhưng thời gian chạy kết quả vẫn không chính xác. Nó sẽ là tốt đẹp ví dụ để có một phương pháp để ngăn chặn trình biên dịch và xem những gì test, cũng như int_return_typefloat_return_type, đã được instantiated với, hoặc những gì instantiations đã thất bại.

Hiện tại chỉ có các tùy chọn có sẵn để gỡ lỗi các mẫu với mức độ chi tiết 1) thông báo lỗi trình biên dịch khi mã không chính xác và 2) kết hợp các trình gỡ rối và trình gỡ lỗi để xem mã được tạo ra gì khi chạy kết quả thời gian không chính xác? Hoặc là có một số tiện ích khác ra có giúp với "xem" làm thế nào các mẫu được instantiated, và xem/kiểm tra những gì mã được tạo ra bởi trình biên dịch để điều tra và gỡ lỗi lỗi mẫu?

+3

khác với 'static_assert' để làm những điều bạn muốn xem lỗi Tôi không nghĩ có bất cứ điều gì để giúp – Flexo

Trả lời

26

Đây là những điều khá cơ bản, nhưng chúng đã làm việc cho tôi trong hầu hết các trường hợp. Tôi quan tâm để xem những gì người khác phải nói quá.

Xin lỗi cho các ví dụ giả tạo.

Sử dụng sandboxes

Bắt đầu với Hố cát nhỏ để kiểm tra mẫu mã như ngay khi nó bắt đầu cư xử lạ hoặc bạn đang làm một cái gì đó phức tạp. Tôi khá thoải mái với các mẫu và tôi vẫn làm điều này gần như ngay lập tức. Đơn giản, nó phát hiện lỗi nhanh hơn. Bạn đã làm nó cho chúng tôi ở đây, vì vậy tôi đoán rằng đây là tranh luận.

Xác định loại tạm thời

temporaries có thể xáo trộn nơi ý định của bạn không được đáp ứng. Tôi đã nhìn thấy rất nhiều mã mà làm một cái gì đó như dưới đây.

template<typename T> 
    T calc(const T &val) { 
    return some_other_calc(val)/100.0; 
    } 

Nói với trình biên dịch loại bạn mong đợi sẽ thất bại nhanh hơn và có khả năng sẽ giúp bạn giải quyết tốt hơn.

template<typename T> 
    T calc(const T &val) { 
    T val_ = some_other_calc(val); 
    return val_/100.0; 
    } 

Sử dụng typeid

Sử dụng typeid(T).name() để in tên mẫu trong báo cáo debug. Điều này sẽ cung cấp cho bạn một chuỗi mà bạn có thể sử dụng để xem cách trình biên dịch quyết định thực hiện loại đó.

template<typename T> 
    typename void test() { 
    std::cout << "testing type " << typeid(T).name() << std::endl; 
    // ... 
    } 

Tránh hiện thực mặc định không cần thiết

Viết mẫu theo cách như vậy mà họ không có việc thực hiện mặc định.

template<typename T, bool is_integral = boost::is_numeric<T>::value > 
    struct my_traits; 

template<typename T> 
    struct my_traits<T, true> { 
    typedef uint32_t cast_type; 
    }; 

template<typename T> 
    void print_whole_number(T &val) { 
    std::cout << static_cast<my_traits<T>::cast_type>(val) << std::endl; 
    } 

này thực thi những người dùng của print_whole_numbermy_traits chuyên môn riêng của họ. Họ sẽ gặp lỗi biên dịch thay vì một nửa số hoạt động vì bạn không thể cung cấp triển khai tốt cho tất cả các loại. Lỗi trình biên dịch sẽ không ngay lập tức hữu ích nếu được sử dụng trong một phần khác biệt của một cơ sở mã, phải thừa nhận.

+9

+1 * Viết mẫu theo cách như vậy mà chúng không có triển khai mặc định * – Manu343726

3

Tôi thích sử dụng trình biên dịch Comeau dựa trên web tuyệt vời để gỡ lỗi. Nó có thể nhận thấy các lỗi về biên dịch chuẩn mà các trình biên dịch khác không thể ...

Comeau có lợi thế lớn là cung cấp nhiều thông báo lỗi dễ đọc hơn GCC hoặc MSVC.

Ngoài ra, hãy nhớ sử dụng static_assert ở mọi nơi nếu có thể - ngay cả khi bạn chắc chắn câu trả lời là đúng sự thật.

+0

BTW, tôi biết đây là một chủ đề nhỏ, nhưng tôi tò mò, mẫu mã của tôi có vẻ để được [biên dịch tốt] (http://ideone.com/zcLmt), hoặc tôi sẽ không đăng nó (không có gì giống như gửi mã mà sẽ không biên dịch) ... những gì cài đặt trong trình biên dịch Comeau là bạn sử dụng? – Jason

+0

@ Jason, chế độ nghiêm ngặt với các tiện ích mở rộng C++ 0x. –

+0

@ Jason, oh ngu ngốc tôi, không dán toàn bộ mã số ^^ –

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