2010-06-12 49 views
7

Tôi đang sử dụng thư viện của bên thứ ba C++ để đặt tất cả các lớp của nó trong không gian tên được phiên bản, hãy gọi nó là tplib_v44. Họ cũng xác định một không gian tên bí danh generic:Bí danh không gian tên C++ và khai báo chuyển tiếp

namespace tplib = tplib_v44; 

Nếu một tiền đạo-khai báo một thành viên của thư viện trong file .h của riêng tôi bằng cách sử dụng không gian tên generic ...

namespace tplib { class SomeClassInTpLib; } 

... tôi nhận được lỗi biên dịch vào tiêu đề trong thư viện của bên thứ ba (hiện đang được đưa vào sau này trong tập tin thực hiện cpp của tôi):

error C2386: 'tplib' : a symbol with this name already exists in the current scope 

Nếu tôi sử dụng không gian tên phiên bản cụ thể, sau đó tất cả mọi thứ hoạt động tốt, nhưng sau đó .. . w mũ là điểm? Cách tốt nhất để giải quyết vấn đề này là gì?

[EDIT] FYI cho người xem trong tương lai, đây là thư viện ICU. Một giải pháp (ít nhất là trong tình huống của tôi) là trong các ý kiến ​​cho câu trả lời được chấp nhận.

Trả lời

4

Dường như có một giải pháp xấu cho việc này, nhưng không có giải pháp tốt.

Đối với ACE (with a decent explanation)Xerces (with a snarky "this is how c++ works" comment), chúng xác định các macro mà bạn có thể sử dụng để thực hiện điều này "chung".

ACE_BEGIN_VERSIONED_NAMESPACE_DECL 
class ACE_Reactor; 
ACE_END_VERSIONED_NAMESPACE_DECL 

XERCES_CPP_NAMESPACE_BEGIN 
class DOMDocument; 
class DOMElement; 
XERCES_CPP_NAMESPACE_END 

Dường như một biểu tượng C++ không may, hãy thử tìm kiếm trong các tplib cho các macro này.

Tiêu chuẩn xử lý các không gian tên và bí danh không gian tên như những thứ khác nhau. Bạn đang khai báo tplib làm không gian tên, do đó khi trình biên dịch cố gắng gán một bí danh sau đó, nó không thể là cả hai, do đó trình biên dịch phàn nàn.

+0

Điều này rất gần với những gì đã kết thúc với tôi. Khi nó bật ra, thư viện của tôi (thư viện ICU) có một tiêu đề nhỏ (uversion.h) - trong số những thứ khác - định nghĩa bí danh không gian tên. Nếu tôi đưa tiêu đề này vào tiêu đề của mình thì tôi có thể sử dụng macro không gian tên phiên bản mà họ xác định (U_ICU_NAMESPACE) trong tệp tiêu đề của tôi và thoát khỏi vùng tên chung trong tệp cpp của tôi. Vì vậy, tôi được cách ly từ những thay đổi cho không gian tên được phiên bản với các phụ thuộc biên dịch thời gian tối thiểu. –

0

Er ... Những gì bạn đang nói xuất hiện ngược lại với tôi. Hoàn toàn ngược lại, điểm cố gắng tuyên bố lớp học của bạn là thành viên của không gian tên tplib là gì? (Hãy quên mất một giây rằng nó thậm chí không phải là một không gian tên, mà là một bí danh không gian tên, đó là lý do tại sao bạn nhận được lỗi.)

Rõ ràng là bạn có một số loại hệ thống điều khiển phiên bản được xây dựng trên các không gian tên và bí danh không gian tên. Nếu lớp của bạn lần đầu tiên được giới thiệu trong một số "phiên bản" cụ thể của không gian tên (như 44) - đó là không gian tên nó phải được khai báo. Tại sao bạn đang cố gắng loại bỏ khai báo lớp của bạn "back in time", tức là thành tất cả các phiên bản trước của không gian tên (như 43 và, ví dụ, 30)? Lớp học của bạn không tồn tại trong các phiên bản trước, vì vậy bạn không được ép buộc nó ở đó.

+1

Tôi đoán câu hỏi ban đầu của tôi không rõ ràng. Bí danh không gian tên được cung cấp bởi nhà phát triển bên thứ ba để tôi có thể tham khảo các lớp của họ dưới dạng 'tplib :: SomeClass'. Họ đang sử dụng không gian tên được phiên bản nội bộ. Vì vậy, trong bản phát hành tiếp theo của họ, không gian tên bên trong có thể là 'tplib_v50'.Nhưng tôi sẽ không phải đi qua tất cả các tập tin của tôi và thay đổi 'tplib_v44 ::' thành 'tplib_v50 ::' bởi vì tôi đang sử dụng bí danh. Tôi không khai báo lớp của mình trong không gian tên; chỉ cần chuyển tiếp một lớp từ thư viện đó trong tệp tiêu đề của các lớp của tôi. Hy vọng rằng có ý nghĩa. –

1

Tôi nghĩ vấn đề của bạn là do tplib là một bí danh chứ không phải là một không gian tên thật

Kể từ khi phiên bản là bên trong một thư viện của bên thứ ba mà bạn không thể sử dụng nó, nhưng sử dụng không gian tên phiên bản bên trong một không phiên bản không gian tên (thay vì đặt bí danh nó) dường như hoạt động với g ++ 4.0.1 và 4.1.2. Tuy nhiên tôi có cảm giác rằng điều này không được phép làm việc ... và có thể có một số vấn đề khác mà tôi không biết.

//This is the versioned namespace 
namespace tplib_v44 
{ 
    int foo(){ return 1; } 
} 

//An unversioned namespace using the versioned one 
namespace tplib 
{ 
    using namespace tplib_v44; 
} 


//Since unversioned is a real namespace, not an alias you can add to it normallly. 
namespace tplib 
{ 
    class Something {}; 
} 


int main() 
{ 
    //Just to make sure it all works as expected 
    tplib::foo(); 
} 
+0

Chỉ cần cẩn thận rằng điều này sẽ không gây ra lỗi nếu 'Cái gì đó 'đã được khai báo trong không gian tên được phiên bản. Nó sẽ âm thầm chấp nhận và 'tplib :: Something' sẽ tham chiếu đến phiên bản đã bỏ qua, bỏ qua' tplib :: Something'. Ngoài ra, ADL sẽ không hoạt động cho các cuộc gọi với 'Something' như một đối số - không gian tên được phiên bản sẽ không được tìm kiếm cho các ứng cử viên. –

+0

@Johannes - Nghe có vẻ hợp lý. Bạn có thể đưa ra một ví dụ về cách ADL sẽ thất bại trong trường hợp sử dụng và không phải là trường hợp không gian tên trực tiếp không? –

0

EDIT: Tôi đã chỉ ra rằng tôi đã bỏ lỡ điểm của câu hỏi - vui lòng bỏ qua!

Bên cạnh các vấn đề được nêu bật trong các câu trả lời khác, nó cũng lo lắng cho tôi một chút rằng bạn đang cố thêm mã của riêng mình vào không gian tên do bên thứ ba xác định ngay từ đầu.

Không gian tên tồn tại để ngăn chặn các ký hiệu xung đột (lớp, typdefs, enums, v.v.), bằng cách đặt chúng vào không gian tên riêng của chúng. Việc thêm mã của riêng bạn vào không gian tên của bên thứ ba có thể gây ra vấn đề nếu (ví dụ) trong phiên bản sau họ quyết định họ cũng muốn sử dụng cùng một biểu tượng (như thêm SomeClassInTpLib) của riêng mình. ngăn chặn sẽ phía sau đầu xấu xí của họ. Đây là lý do tại sao nó thường là thực hành xấu để thêm vào không gian tên std.

Một giải pháp an toàn hơn nhiều để tránh vấn đề hoàn toàn là chỉ cần sử dụng không gian tên của riêng bạn. Gọi nó là tplib_ex hoặc một cái gì đó tương tự và hiệp hội vẫn sẽ được rõ ràng, nhưng xung đột sẽ không phải là một vấn đề và vấn đề liên quan đến bí danh của bạn cũng sẽ biến mất.

+0

Anh ấy không thêm biểu tượng vào thư viện, anh ấy đang cố chuyển tiếp các đối tượng khai báo đã tồn tại trong không gian tên bên thứ ba (bí danh). – Stephen

+0

Ah, thật vậy. Bằng cách nào đó đã bỏ lỡ điều đó. Cảm ơn vì sự đúng đắn của bạn. – Mac

0

điểm là gì?

Ngăn chặn bạn từ việc thêm những thứ bổ sung trong không gian tên của họ, có lẽ vì họ nghĩ thêm tên nhiều hơn nữa sớm (và thực tế họ đang sử dụng một không gian tên là phiên bản có thể gợi ý đó). Tuy nhiên đây chỉ là những suy đoán. Điều này có tác dụng phụ của việc ngăn ngừa các khai báo chuyển tiếp trong không gian tên mà bạn nghĩ là hợp lý hơn, vì vậy tôi nghĩ rằng đó chỉ là thực hành lập trình kém ở bên cạnh chúng.

Cách tốt nhất để giải quyết vấn đề này là gì?

Không có cách nào tốt nhất, nhưng cố gắng tránh sử dụng macro, macro rất xấu và không đẹp để xem (Tôi không thích tất cả nội dung chữ hoa). Nếu bạn lo lắng về "điều gì sẽ xảy ra khi họ thay đổi phiên bản?" (vâng trong lý thuyết bạn phải thay đổi "v44" thành "v45" trong tất cả mã của bạn)

sau đó chỉ sử dụng 1 tiêu đề đơn để chuyển tiếp khai báo mọi thứ bạn cần.

TpLibForwards.hpp

#ifdef XXXXXX_TPLIB 
    #error "XXXXXX_TPLIB is already taken, change to something else" 
#endif 
#define XXXXXX_TPLIB tplib_v44 
//... and that's why I don't like keeping macros around.. 

namespace XXXXXX_TPLIB 
{ 

    // FORWARD DECLARATIONS 
    class A1; 
    class A2; 
    //... 
} 
namespace tplib = XXXXXX_TPLIB; 
#undef XXXXXX_TPLIB 

Nếu họ thay đổi thư viện sau đó bạn chỉ cần áp dụng 1 sự thay đổi và trong 1 file. Nhiều lập trình viên đã tiếp tục khai báo trong một thời điểm vì nó dễ quản lý hơn và trong trường hợp bạn phải chuyển tiếp nhiều thứ bạn giữ các tiêu đề khác sạch hơn và dễ đọc hơn.

#include <TpLibForwards.hpp> // my forwards declarations 
Các vấn đề liên quan