У меня проблема с довольно простым кодом с VS 2012. Я тестировал этот код на CentOS 7, Debian 8, 9, Fedora 25, 26, 27, 28 и Ubuntu 14.04, 16.04, 18.04 как с последними компиляторами GCC и Clang в официальные пакеты, а также на VS 2013, VS 2015, VS 2017. Работает.
Вот минимальная версия инкриминируемого кода:
namespace B {
enum bar {
HELLO,
WORLD
};
}
namespace A {
namespace B {
// Some stuff
}
}
#include "file0.h"
namespace A {
namespace C {
template<::B::bar = ::B::HELLO> class foo {
// Some stuff
};
}
}
#include <iostream>
#include "file0.h"
#include "file1.h"
#include "file2.h"
int main() {
::A::C::foo<> myFoo;
// Some stuff
}
Этот код приводит к следующей ошибке компиляции в VS 2012:
error C2039: 'bar' : is not a member of 'A::B'
Поскольку мы находимся в пространстве имен ::A::C
в file2.h (и, следовательно, в пространстве имен ::A
) и запрашиваем пространство имен ::B
, кажется, что VS 2012 игнорирует ::
перед B
и сначала выполняет поиск в текущем пространстве имен ::A
. Поскольку он не находит bar
в ::A::B
, он просто выдает ошибку вместо поиска в областях более высокого уровня.
Учитывая следующий ответ при переполнении стека, похоже, в VS 2012 есть ошибка с разрешением пространства имен.
Мои вопросы:
Есть ли способ решить эту проблему, не меняя имена пространств имен (для меня очень важно, чтобы B находился в :: B и :: A :: B)? Например, использование другого синтаксиса для использования пространства имен или использование псевдонимов пространств имен?
Примечание: код для воспроизведения ошибки был отредактирован (на самом деле это третий файл file0.h по сравнению с моим исходным постом. Моя ошибка).
Я пытался воспроизвести вашу проблему на godbolt.org. В вашем MCVE в main()
есть небольшая ошибка: это должен быть A::B::foo<> myFoo;
. С этим небольшим исправлением я не смог воспроизвести в MSVC 19 2015. (Более старая версия, к сожалению, недоступна - или я ее не узнал.)
странно, что он также отлично компилируется в Visual Studio 2008.
Извините, вы правы, я забыл A :: B :: foo <> в main. Я редактирую.
ОШИБКА: мое простое воспроизведение ошибки на самом деле не совсем точное. Я редактирую (задействовано третье пространство имен).
@Scheff действительно в посте я допустил еще одну ошибку, включив file1.h вместо file0.h. Я только что редактировал. К сожалению, это обходное решение невозможно, поскольку все файлы, представленные здесь, находятся в разных пакетах.
Помогает ли обходной путь typedef
(предлагается в ответе П.Е. Нормандса)?
Я совершенно не понимаю, что шаблоны К сожалению, это обходное решение невозможно, поскольку все файлы, представленные здесь, находятся в разных пакетах. должны быть "видимыми" во время компиляции. Без включения зависимостей нельзя создать экземпляр шаблона. (В некоторых случаях он даже не может быть скомпилирован, но это может быть связано с ошибками в MSVC. В компиляторе MSVC есть много слабых мест, касающихся шаблонов. Недавно я прочитал заявление о том, что они усердно работают, чтобы переписать эту часть компилятора полностью, хотя это, вероятно, касается только последней версии.)
@Scheff Я имею в виду, что здесь file2.h
знает file0.h
, но я не могу передать информацию о file1.h
в file2.h
. Однако file1.h
необходим для других вещей в программе. Вот почему эта ошибка довольно странная: в file2.h
возникает ошибка, связанная с file1.h
, в то время как единственное, что у них есть общего, - это сосуществование во всей программе, но никак не связано.
... и, боюсь, есть определенные причины не переходить хотя бы с VS2012 на VS2013?
Это решило бы множество проблем, но наш проект на данный момент должен быть совместим с VS 2012 (но со всеми проблемами, вызванными VS 2012, мы, вероятно, перестанем пересматривать это)
Мне не удалось воспроизвести эту ошибку на visual 2013 и 2008 гг. Вроде бы конкретная проблема 2010 и 2012 годов.
Возможно, попробуйте typedef вне объявления пространства имен:
namespace B {
enum bar {
HELLO,
WORLD
};
}
typedef ::B::bar my_type;
namespace A {
namespace B {
template<my_type= ::B::WORLD> class foo {
};
}
}
int main(int argc, char* argv[])
{
A::B::foo<> myFoo;
}
Я изменил код, чтобы воспроизвести ошибку (исходный код на самом деле был неправильным). Однако вы не можете воспроизвести ошибку на VS 2013, она не работает для меня только на VS 2012 (я не пробовал более старые VS).
Я думаю, вы забыли A :: B :: foo <> вместо foo <>. Но это не должно изменить ваш вопрос. Протестировал ваш код в Visual Studio 2013, и он отлично компилируется.