Мне дали код, который прекрасно компилируется на MSVC, и я пытаюсь заставить его скомпилировать на Clang в Xcode. В настоящее время я сталкиваюсь с проблемой, при которой класс переопределяется с помощью следующего определения типа:
typedef std::map<MyNS::istring, EntityState> Entity;
Глядя на предварительно обработанный вывод, я вижу, что есть две предварительные декларации class Entity
до этого typedef. Тем не менее, фактическое определение class Entity
не находится в предварительно обработанном выводе, но находится в том же пространстве имен, что и новая карта сущностей (не MyNS
хоть…). Это предварительные декларации, которые вызывают эту ошибку? И есть ли какой-то способ, которым это может быть допустимо в MSVC и не работает из-за педантизма Clang?
РЕДАКТИРОВАТЬ: У меня нет MSVC под рукой, но вот фрагмент, который я собрал, чтобы продемонстрировать, какую ошибку я получаю (я упростил определения так, чтобы все это помещалось в небольшом пространстве). Это вызывает ту же ошибку, что и я, когда я пытаюсь скомпилировать его с помощью Clang. Будет ли это работать в MSVC?
namespace TheNS {
class Entity;
struct EntityState
{
std::string aString, anotherString;
int anInt;
EntityState() {}
EntityState(std::string a, std::string b, int i)
{
// constructor
}
};
typedef std::map<std::string, EntityState> Entity;
class Entity
{
public:
void SomeFunction();
private:
int m_aVar;
};
}
Да, это не правильно. Никогда не должен компилироваться, если он компилируется в MSVC — возможно, это ошибка компилятора. Предварительное объявление сообщает компилятору, что TheNS::Entity
будет классом и ничего более (не enum, union или typedef). На самом деле, ваш код такой же, как
class Entity;
typedef int Entity;
Конечно это неверно.
N3337 9,1 / 2
Объявление, состоящее исключительно из идентификатора ключа класса; это либо переопределение имени
в текущей области или в предварительном объявлении идентификатора в качестве имени класса. Он вводит имя класса
в текущем объеме.
Итак, после этого
class Entity;
компилирует знает, что Entity
будет использоваться в качестве имени класса. Это имя может быть объявлено как функция (в той же области видимости), в этом случае вам следует использовать class Entity
когда вы хотите использовать Entity
класс (или переопределить Entity
имя по typedef, как сказано в комментариях).
7.1.3 / 6
В данном контексте спецификатор typedef не должен использоваться для переопределения имени любого типа, объявленного в этом
область, чтобы обратиться к другому типу. [ Пример:class complex { /∗ ... ∗/ }; typedef int complex; // error: redifinition
— конец примера]
Других решений пока нет …