2016-05-17 13 views
7

Trong this presentation vào khoảng 00:19:00, Andrei Alexandrescu giải thích việc triển khai macro SCOPE_EXIT của mình. Ông tạo ra một đối tượng ScopeGuard trên stack mà thực hiện một lambda tiêu hủy:Làm cách nào để __COUNTER__ có thể gây ra vi phạm ODR ở đây?

#define ANONYMOUS_VARIABLE(str) \ 
    CONCATENATE(str, __COUNTER__) 

namespace detail { 
    enum class ScopeGuardOnExit {}; 
    template <typename Fun> 
    ScopeGuard<Fun> 
    operator+(ScopeGuardOnExit, Fun&& fn) { 
     return ScopeGuard<Fun>(std::forward<Fun>(fn)); 
    } 
} 

#define SCOPE_EXIT \ 
    auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \ 
    = ::detail::ScopeGuardOnExit() + [&]() 

Cho đến nay, quá nổi tiếng (ông thậm chí khẳng định trong slide của mình rằng đây là một chiếc mũ cũ). Việc sử dụng trông như thế này:

void foo() 
{ 
    SCOPE_EXIT{ printf("foo exits"); }; 
} 

Nhưng tại 01:04:00, Chandler Carruth tuyên bố rằng việc sử dụng này của __COUNTER__ vĩ mô để tạo ra một cái tên "vô danh" sẽ gây ra vi phạm ODR khi được sử dụng trong một hàm inline. Điều này có đúng không? Macro chỉ được sử dụng để tạo tên biến cục bộ, không phải tên loại hoặc thứ gì đó, vậy làm thế nào điều này có thể gây ra vi phạm ODR?

Trả lời

8

Giả sử hàm nội tuyến nằm trong tiêu đề được bao gồm trong hai đơn vị dịch khác nhau và giá trị của bộ đếm xảy ra ở một giá trị khác nhau trong mỗi đơn vị dịch.

Sau đó, bạn có hai định nghĩa của hàm nội tuyến với các tên khác nhau cho biến. Đó là vi phạm ODR - bạn phải sử dụng cùng một chuỗi mã thông báo cho mọi định nghĩa.

(Mặc dù trong thực tế tôi sẽ rất ngạc nhiên nếu nó gây ra bất kỳ vấn đề.)

+0

Tôi chỉ đến cùng một kết luận, đã cho tôi một thời gian để nhận ra rằng đó là về định nghĩa của hàm riêng của mình. Nhưng điều này có ý nghĩa, ngay cả khi nó chỉ là về một tên biến khác. Tôi đoán người ta chỉ có thể hy vọng rằng điều này không gây ra bất kỳ vấn đề ... có lẽ các macro LINE sẽ là một lựa chọn tốt hơn ở đây? – Horstling

+0

Có, trừ khi bạn muốn khai báo nhiều hơn một trong những thứ đó trên một dòng. (Hoặc bạn đang rối tung với '# line'.) –

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