Потянув стандартную библиотеку C / C ++ в пространство имен вашего проекта, хорошо? - PullRequest
2 голосов
/ 15 мая 2011

Я портирую некоторый открытый исходный код, чтобы он мог основываться на другом компиляторе c ++.Одной из трудностей и тем, которые, похоже, продолжают появляться, являются различия в реализации предоставляемой стандартной библиотеки компилятором.

Например, один из исходных файлов, которые я компилирую, включает <sys/types.h>.Однако, это дает мне следующие ошибки:

Error E2316 g:\Borland\BCC593\Include\sys/types.h 45: 'time_t' is not a member of 'std'
Error E2272 g:\Borland\BCC593\Include\sys/types.h 45: Identifier expected

Изучив основную причину этого, я обнаружил, что один из главных заголовков включения проекта включает <sys/types.h> в этот шаблон:

project_source1.cpp:

#include "../TargetPlatform.h"
#include "project_config.h"
#include <windows.h>

namespace project_namespace {
#include "project_component/all.h"
// more project includes down here
// ...
}

project_component / all.h:

#ifndef INCLUDE_GUARDS
#define INCLUDE_GUARDS

#include <sys/types.h>
#include "project_header1.h"
#include "project_header2.h"
// and other headers etc..
// followed with class definitions and what not.

#endif

Это все хорошо, за исключением одной проблемы, <sys/types.h> реализован примерно такэто для компилятора, который я портирую на:

<sys/types.h>, урезанный до сути:

namespace std {

typedef long time_t;
typedef short dev_t;
typedef short ino_t;
typedef short mode_t;
typedef short nlink_t;
typedef int   uid_t;
typedef int   gid_t;
typedef long  off_t;

} // std

using std::time_t;
using std::dev_t;
using std::ino_t;
using std::mode_t;
using std::nlink_t;
using std::uid_t;
using std::gid_t;
using std::off_t;

И это причина ошибки компиляции, которую я вижу.Поскольку проект включает <sys/types.h> внутри своего собственного пространства имен, такие вещи, как time_t, off_t, dev_t и т. Д., Помещаются в область действия project_namespace::std::, что явно не соответствует тому, что предполагалось.

Что такоелучший способ справиться с этим?Имейте в виду, что могут быть другие стандартные заголовки библиотек, определенные аналогичным образом, а не просто sys/types.h.Существуют ли какие-либо идиомы С ++, которые имеют отношение или частично связаны с этой проблемой (или, возможно, даже расходятся с ней из-за способа, которым это реализовано)?Если да, то как это можно примирить?

Спасибо

Ответы [ 2 ]

7 голосов
/ 15 мая 2011

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

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

Если вам нужно уметьчтобы легко переименовать ваше пространство имен или использовать один и тот же заголовок для объявления одних и тех же символов в нескольких различных пространствах имен в зависимости от контекста, используйте препроцессор, чтобы изменить имя пространства имен.Это крайне уродливо, но гораздо лучше, чем то, что вы делаете в настоящее время.

В качестве быстрого и грязного решения вы можете сделать одну вещь: #include <sys/types.h> и любой другой системный заголовок, который находится перед пространством имендекларация.Это приведет к срабатыванию защитников двойного включения в системных заголовочных файлах и позволит избежать объявления чего-либо внутри пространства имен.

1 голос
/ 15 мая 2011

Я бы сказал, что вам нужно изменить код ошибки, чтобы стандартные типы больше не определялись в project_namespace.

Мне кажется, у вас есть две основные проблемы: [1] у вас есть универсальный заголовок в project_all.h и [2] он #include d внутри namespace project_namespace. Сначала я расскажу о последнем. Если у вашего проекта есть вещи, которые он хочет поместить в собственное пространство имен, это нормально, но это должно быть сделано следующим образом:

// Foo.h
// includes go here
namespace project_namespace {
    class Foo { ... }
}
// Foo.cpp
// includes go here
namespace project_namespace {
    // Foo implementation goes here
}

... другими словами, в заголовочных файлах и файлах реализации ваших классов должно быть указано, к какому пространству имен принадлежат эти классы, как бы к "пространству имен". Все ваши #include находятся вне namespace, потому что заголовочный файл для каждого класса объявляет пространства имен, к которым принадлежит класс. Это соглашение, используемое стандартной библиотекой.

Теперь, если вы все еще хотите использовать project_all.h, вы можете сделать это. Без пространства имен - потому что каждый заголовочный файл будет помещать свои объявления в пространство имен, которое он хочет (или нет).

Но было бы лучше обойтись без project_all.h; вместо этого #include заголовочные файлы индивидуально и делают зависимости явными. И если ответ «слишком много заголовочных файлов», это, вероятно, признак высокой степени связи между вашими компонентами.

Я понимаю, что это, вероятно, не тот ответ, который вы хотели, извините ...

...