2013-08-08 17 views
7

Mam problem, który involes zagnieżdżone przestrzenie nazw i klasy szablonów. Udało mi się również stworzyć przypadek testowy, który powoduje ten sam błąd, co rzeczywisty kod, ale jest bardziej czytelny.Zagnieżdżone przestrzenie nazw i niejednoznaczny symbol

Kompilacja następujący kod przy użyciu VS2012 z platformą toolset 2010 powoduje błąd:

namespace A 
{ 
    namespace B 
    { 
     namespace C1 
     { 
     struct SMeasResult{}; 
     } 
     namespace C2 
     { 
     struct SMeasResult{}; 
     } 
    } 
} 

namespace C1Test 
{ 
    using namespace A::B::C1; 

    template<typename T> 
    class Fook 
    { 
    public: 

     void Yu() 
     { 
     SMeasResult Field; 
     } 
    }; 
} 

namespace C2Test 
{ 
    using namespace A::B::C2; 

    template<typename T> 
    class Fook 
    { 
    public: 

     void Yu() 
     { 
     SMeasResult Field; 
     } 
    }; 
} 

void m(){ 
    C1Test::Fook<int> yu; 
    C2Test::Fook<int> me; 

    yu.Yu(); 
    me.Yu(); 
} 

Specyficzny błędu jest następująca:

1>------ Build started: Project: MultiVicomTest (Visual Studio 2010), Configuration: Debug Win32 ------ 
1> test.cpp 
1>c:\code\test.cpp(27): warning C4101: 'Field' : unreferenced local variable 
1>   c:\code\test.cpp(26) : while compiling class template member function 'void C1Test::Fook<T>::Yu(void)' 
1>   with 
1>   [ 
1>    T=int 
1>   ] 
1>   c:\code\test.cpp(49) : see reference to class template instantiation 'C1Test::Fook<T>' being compiled 
1>   with 
1>   [ 
1>    T=int 
1>   ] 
1>c:\code\test.cpp(43): error C2872: 'SMeasResult' : ambiguous symbol 
1>   could be 'c:\code\test.cpp(11) : A::B::C2::SMeasResult' 
1>   or  'c:\code\test.cpp(7) : A::B::C1::SMeasResult' 
1>   c:\code\test.cpp(42) : while compiling class template member function 'void C2Test::Fook<T>::Yu(void)' 
1>   with 
1>   [ 
1>    T=int 
1>   ] 
1>   c:\code\test.cpp(50) : see reference to class template instantiation 'C2Test::Fook<T>' being compiled 
1>   with 
1>   [ 
1>    T=int 
1>   ] 
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ========== 

Nie rozumiem dlaczego symbol 'SMeasResult' byłby niejednoznaczny dla kompilatora, ponieważ jest używany w oddzielnej przestrzeni nazw. Do tej pory mogłem się dowiedzieć, że problem ten pojawia się tylko wtedy, gdy zajęcia są klasami szablonowymi. Ten sam problem nie pojawia się, gdy definicja szablonu zostanie usunięta.

Czy ktoś może mi powiedzieć, czy zrobiłem coś nie tak?

+1

Jestem prawie pewien, że to błąd. Gcc i clang kompilują to dobrze i nie rozumiem, dlaczego byłaby ona niejednoznaczna. – jrok

+1

MSVC nigdy nie zaimplementowało dwufazowego wyszukiwania nazw używanych w szablonach zgodnie z normami językowymi od C++ 98. Ten błąd jest najprawdopodobniej jego następstwem. – Casey

Odpowiedz

2

To właściwie wygląda na błąd kompilatora. Kiedy weźmiesz pod uwagę, że wersja funkcji skompilowana bez niejasności, podejrzewam, że w jakiś sposób korzystanie z przestrzeni nazw w ramach namespace C1Test pozostaje nawet w przestrzeni nazw .

Zostało to dodatkowo potwierdzone przez fakt, że g ++ 4.4 i 4.5 mogą skompilować ten kod dobrze.

+1

Tak, wykorzystanie zostało ujawnione w obrazie, a nie w g ++. Ponieważ nie jestem wielkim fanem tego słowa kluczowego, nie wiem, co mówią o nim standardy. – Uman

+1

Co ciekawe, zmiana kolejności kodu z przestrzeni nazw "C2Test" przed "C1Test" powoduje, że "niejednoznaczność" * nadal * jest zgłaszana dla 'SMeasResult' wewnątrz' C2Test'. Fakt, że deklaracja w "C1" pojawia się przed "C2" wydaje się być ważniejsza niż kolejność zastosowań. – Casey

+0

Mój błąd - ważna jest kolejność instancji szablonów, a nie żadnych deklaracji. Drugi szablon, który ma być utworzony, zostaje "obciążony" za błąd niezależnie od kolejności deklaracji "C1", "C2", "C1Test" lub "C2Test". – Casey

0

Spróbuj użyć używając A :: B :: C1 :: SMeasResult; i przy użyciu A :: B :: C2 :: SMeasResult; w przestrzeniach C1Test i C2Test. To rozwiązuje problem.

BTW Dlaczego potrzebujesz tak wiele przestrzeni nazw? STL jest bardzo duży, ale wykorzystuje tylko 1 przestrzeń nazw - std.

+0

Funkcja Boost jest również duża i wykorzystuje wiele przestrzeni nazw;) –

+0

W tym konkretnym przypadku mamy dużą bazę kodów zawierającą kod dotyczący różnych rodzajów technologii radiowych. Chcemy przenieść odpowiednie klasy do przestrzeni nazw, które przypominają technologię, którą reprezentują, stąd potrzeba wielu przestrzeni nazw. Ze względu na integrację wielu innych platform (.NET, Java), wybraliśmy sposób podobny do nich (pomyśl tylko o ogromnej ilości przestrzeni nazw na tych platformach). – Simon