защита #include в пространстве имен {} блок?

Править: Я знаю, что метод 1 чрезвычайно недопустим и будет, вероятно, использовать метод 2, но я ищу лучший взлом или лучшее решение смягчить необузданное, изменяемое быстрое увеличение пространства имен.

У меня есть несколько класс или определения метода в одном пространстве имен, которые имеют различные зависимости и хотели бы использовать наименьшее количество блоков пространства имен или явных возможных обзоров, но при группировке #include директив с определениями, которые требуют их максимально лучше всего. Я никогда не видел признака, что любому препроцессору можно было сказать исключить пространство имен {} определяющий объем от #include содержания, но я здесь, чтобы спросить, возможно ли что-то подобное этому: (см. нижнюю часть для объяснения того, почему я хочу что-то очень простое),

// NOTE: apple.h, etc., contents are *NOT* intended to be in namespace Foo!

// would prefer something most this:
#pragma magic_namespace_backout(1) // FIXME: use actually existing directive
namespace Foo {

#include "apple.h"
B *A::blah(B const *x) { /* ... */ }

#include "banana.h"
int B::whatever(C const &var) { /* ... */ }

#include "blueberry.h"
void B::something() { /* ... */ }

} // namespace Foo

...

// over this:
#include "apple.h"
#include "banana.h"
#include "blueberry.h"

namespace Foo {
B *A::blah(B const *x) { /* ... */ }
int B::whatever(C const &var) { /* ... */ }
void B::something() { /* ... */ }
} // namespace Foo

...

// or over this:
#include "apple.h"
namespace Foo {
B *A::blah(B const *x) { /* ... */ }
} // namespace Foo

#include "banana.h"
namespace Foo {
int B::whatever(C const &var) { /* ... */ }
} // namespace Foo

#include "blueberry.h"
namespace Foo {
void B::something() { /* ... */ }
} // namespace Foo

Моя настоящая проблема состоит в том, что у меня есть проекты, где модуль, возможно, должен перейтись, но имеет сосуществующие компоненты от ответвлений в той же программе. У меня есть классы как FooA, и т.д., что я позвонил Foo:: в способности надежд перейти менее мучительно как Foo:: v1_2:: A, где некоторой программе, возможно, понадобятся оба Нечто:: A и Нечто:: v1_2:: A. Я хотел бы "Нечто" или "Foo:: v1_2" для разоблачения только действительно однажды на файл, как блок единого пространства имен, если это возможно. Кроме того, я склонен предпочитать определять местоположение блоков #include директив сразу выше первого определения в файле, который требует их. Каков мой лучший выбор, или альтернативно, что я должен делать вместо того, чтобы угнать пространства имен?

17
задан Jeff 19 May 2010 в 21:08
поделиться

6 ответов

Просто подумайте о #including как о копировании и вставке содержимого включаемого файла в позицию директивы #include.

Это означает, что да, все во включенном файле будет внутри пространства имен.

38
ответ дан 30 November 2019 в 10:21
поделиться

Вопрос: Вы можете:
A: Да, можно.Оператор include выполняется во время предварительной обработки еще до того, как компилятор увидит его.

Q: Это хорошая идея.
A: Наверное, нет.

Что произойдет, если вы #include Apple.g без тегов пространства имен.
теперь у вас есть яблоки, объявленные в глобальном пространстве имен, а также в пространстве имен foo.

Вы должны стараться избегать ситуаций, когда вы, пользователь вашего кода, должны понимать, как его следует использовать. Если в вашей документации указано: всегда #include заголовочный файл Apple внутри пространства имен foo, это бит, который пользователь не будет читать, и вызовет много часов путаницы.

16
ответ дан 30 November 2019 в 10:21
поделиться

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

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

2
ответ дан 30 November 2019 в 10:21
поделиться

Вероятно, каждый модуль должен ссылаться на класс «Foo :: A», и вы можете поместить определение макроса в начало модуля, которому нужна другая версия «A».

#include "apple.h"
#include "apple1_2.h"

//this module uses Version 1.2 of "Apple" class
#define Apple v1_2::Apple
namespace Foo {
B *A::blah(B const *x) 
{
    Foo::Apple apple; //apple is of type Foo::v1_2::Apple
    /* ... */ 
} 
int B::whatever(C const &var) { /* ... */ }
void B::something() { /* ... */ }
} // namespace Foo
#undef Apple

Но это затрудняет понимание кода. Возможно, если вам нужно выбирать между реализациями объекта, вам лучше использовать фабричную функцию. Это сделало бы ваше намерение явным во всем коде.

AppleBaseClass* createApple(int version)
{
    if(version == 0)
        return new Foo::Apple;
    else if(version == 1)
        return new Foo::v1_2::Apple;
}
//usage
AppleBaseClass* apple = createApple(apple_version);

//compile-time equivalent
//metafunction CreateApple
template<int version> struct CreateApple {};
template<>
struct CreateApple<0> 
{
    typedef Foo::Apple ret;
};
template<>
struct CreateApple<1> 
{
    typedef Foo::v1_2::Apple ret;
};
//usage
CreateApple<apple_version>::ret apple;
0
ответ дан 30 November 2019 в 10:21
поделиться

Вы редактировали этот вопрос?

Первый блок в ваших примерах невозможен. Вы не можете подняться по пространству имен или чему-либо еще из него, как хотите, и не можете отключить пространство имен из файла, включенного в этот блок пространства имен. Так просто невозможно.

Лично я предпочитаю первую из ваших альтернатив.

Отредактируйте, хорошо ... вот кое-что, что вы могли бы сделать (может потребоваться очистка, непроверено):


#define MY_NAMESPACE Foo
#define NAMESPACE_WRAP(X) namespace MY_NAMESPACE { X }

#include "apple.h"
NAMESPACE_WRAP((B * A::blah(B const * x) {...}))

Я почти уверен, что NAMESPACE_WRAP не будет работать для такого рода вещей, поэтому вам, вероятно, придется поместить его в другой header или ".ipp" или что-то еще и сделайте следующее:


#define NAMESPACE_WRAP(HEADER) \
namespace MY_NAMESPACE { \
#include HEADER \
}

Даже это может не сработать, и вам придется выйти за рамки моих знаний и посмотреть, как библиотека метапрограммирования препроцессора boost выполняет свои макросы. На самом деле вы можете обнаружить, что эта библиотека в конечном итоге упрощает то, что вы хотите.

В любом случае, он не будет ни таким красивым, как вы хотите, ни, ИМХО, таким читабельным и понятным, как первая альтернатива, которую вы представили.

2
ответ дан 30 November 2019 в 10:21
поделиться

Метод 2 полностью.
Я всегда работаю с этими простыми правилами:

1.) Исходный код должен быть ЧИСТЫМ, ЛЕГКОМ ДЛЯ ПОНИМАНИЯ и ЛЕГКИМ-ДОКАЗАТЕЛЬНЫМ.
-Хороший продукт создается не одним человеком. Простое, интуитивно понятное и понятное форматирование сделает жизнь каждого человека счастливее.

2.) Если в конечном продукте не будет разницы в производительности, придерживайтесь правила №1
-Для разработчика нет смысла тратить мозги на то, что не приносит пользы конечному потребителю.

3.) Элегантный дизайн всегда работает хорошо, поэтому правило № 2 всегда остается в силе.
-То же правило относится и к Богу, возьми зеркало и посмотри на себя :)

0
ответ дан 30 November 2019 в 10:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: