Псевдоним пространства имен C ++ и предварительное объявление - PullRequest
9 голосов
/ 12 июня 2010

Я использую стороннюю библиотеку C ++, которая помещает все свои классы в версионное пространство имен, назовем это tplib_v44. Они также определяют общий псевдоним пространства имен:

namespace tplib = tplib_v44;

Если предварительно объявить члена библиотеки в моем собственном .h файле, используя общее пространство имен ...

namespace tplib { class SomeClassInTpLib; }

... Я получаю ошибки компилятора в заголовке сторонней библиотеки (которая позже будет включена в мой файл реализации .cpp):

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

Если я использую пространство имен для конкретной версии, тогда все работает нормально, но тогда ... какой смысл? Какой лучший способ справиться с этим?

[EDIT] К вашему сведению для будущих зрителей, это была библиотека ICU. Решение (по крайней мере, в моей ситуации) - в комментариях к принятому ответу.

Ответы [ 5 ]

4 голосов
/ 12 июня 2010

Похоже, что для этого есть некрасивый обходной путь, но нет хорошего решения.

Для ACE (с приличным объяснением) и Xerces (со странным комментарием "так работает c ++") , они определяют макросы, которые вы можете использовать для этого " в общем».

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

Это похоже на неудачный артефакт c ++, попробуйте поискать в вашем tplib эти макросы.

Стандарт рассматривает пространства имен и псевдонимы пространства имен как разные вещи. Вы объявляете tplib пространством имен, поэтому, когда компилятор пытается назначить псевдоним позже, он не может быть и тем и другим, поэтому компилятор жалуется.

2 голосов
/ 12 июня 2010

Я думаю, что ваша проблема в том, что tplib является псевдонимом, а не реальным пространством имен

Поскольку управление версиями находится внутри сторонней библиотеки, вы, возможно, не сможете ее использовать, но использование версионного пространства имен в неверсированном пространстве имен (а не наложение его имен), похоже, работает для g ++ 4.0.1 и 4.1.2. Однако я чувствую, что это не должно работать ... и, возможно, есть некоторые другие проблемы, о которых я не знаю.

//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 голосов
/ 17 ноября 2016

в чем смысл?

Запрещает вам добавлять дополнительные вещи в их пространство имен , возможно, потому что они думают добавить гораздо больше имен в ближайшее время (и тот факт, что онииспользование версионного пространства имен может предложить это).Однако это только предположения.Это имеет побочный эффект - предотвращение предварительных объявлений в пространстве имен, которые вы считаете более разумными, поэтому я считаю, что это просто плохая практика программирования с их стороны.

Какой лучший способ справиться с этим?

Не самый лучший способ, но старайтесь избегать использования макросов, макросы некрасивые и не очень приятные для просмотра (мне не нравятся все эти заглавные буквы).Если вы беспокоитесь о том, "что происходит, когда они меняют версию?"(да, теоретически вы должны изменить «v44» на «v45» во всем вашем коде)

, а затем просто использовать 1 единственный заголовок для прямого объявления всего, что вам нужно.

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

Если они меняют библиотеку, то вам просто нужно применить 1 изменение и 1 файл.Многие программисты уже поддерживают переадресацию деклараций в одном месте, потому что это намного более управляемо, и в случае, если вам придется пересылать декларации, вы сохраняете других заголовков чище и намного более читабельными .

#include <TpLibForwards.hpp> // my forwards declarations
0 голосов
/ 12 июня 2010

РЕДАКТИРОВАТЬ: мне было указано, что я упустил суть вопроса - пожалуйста, не стесняйтесь игнорировать!

Помимо проблем, отмеченных в других ответах, меня также немного беспокоит то, что вы пытаетесь добавить свой собственный код в пространство имен, определенное третьей стороной.

Пространства имен существуют для предотвращения конфликтов конфликтующих символов (классов, typdefs, перечислений и т. Д.), Помещая их в собственное пространство имен, тем самым создавая уникальный полностью определенный символ из потенциально идентичных частично определенных символов. Добавление собственного кода в пространство имен третьей стороны может вызвать проблемы, если (например) в более поздней версии они решат, что они тоже хотят использовать один и тот же символ (например, добавив свой собственный SomeClassInTpLib) - внезапно, пространства имен конфликтов имен Предотвращение приведет к появлению уродливой головы. Вот почему обычно плохо добавлять в пространство имен std.

Гораздо более безопасное решение, позволяющее полностью избежать этой проблемы, - просто использовать собственное пространство имен. Назовите это tplib_ex или что-то подобное, и связь все равно будет ясна, но конфликт не будет проблемой, и проблема, связанная с псевдонимом, также исчезнет.

0 голосов
/ 12 июня 2010

Э-э ... То, что вы говорите, кажется мне задом наперед.Напротив, какой смысл пытаться объявить свой класс членом tplib пространства имен?(На секунду забываем, что это даже не пространство имен, а псевдоним пространства имен, поэтому вы получаете сообщение об ошибке.)

Очевидно, что у вас есть какая-то система контроля версий, построенная напространства имен и псевдонимы пространства имен.Если ваш класс впервые представлен в некоторой конкретной «версии» пространства имен (например, 44) - это пространство имен, в котором он должен быть объявлен. Почему вы пытаетесь засунуть объявление своего класса «вовремя», то есть в все прошлые версии пространства имен (например, 43 и, скажем, 30)?Ваш класс не существовал в предыдущих версиях, поэтому вы не должны его там форсировать.

...