2016-12-15 8 views
5

Poniższy kod nie skompilować pod gcc 5.3 (jest to zmniejszona wersja pochodzi z większego kawałka kodu):własnym referential wykorzystanie unordered_map powoduje problemy dla gcc 5.3, ale nie dzyń

#include <unordered_map> 
#include <string> 

class Foo { 
    std::unordered_map<std::string, Foo> m; //"self-referential" 
}; 

int main() 
{ 
    Foo f; 
    return 0; 
} 

z następujące błędy:

g++ --std=c++1y -c rh.cpp 

In file included from /usr/local/include/c++/5.3.0/utility:70:0, 
       from /usr/local/include/c++/5.3.0/unordered_map:38, 
       from rh.cpp:1: 
/usr/local/include/c++/5.3.0/bits/stl_pair.h: In instantiation of ‘struct std::pair<const int, Foo>’: 
/usr/local/include/c++/5.3.0/ext/aligned_buffer.h:85:34: required from ‘struct __gnu_cxx::__aligned_buffer<std::pair<const int, Foo> >’ 
/usr/local/include/c++/5.3.0/bits/hashtable_policy.h:246:43: required from ‘struct std::__detail::_Hash_node_value_base<std::pair<const int, Foo> >’ 
/usr/local/include/c++/5.3.0/bits/hashtable_policy.h:292:12: required from ‘struct std::__detail::_Hash_node<std::pair<const int, Foo>, false>’ 
/usr/local/include/c++/5.3.0/bits/hashtable_policy.h:1896:60: required from ‘struct std::__detail::_Hashtable_alloc<std::allocator<std::__detail::_Hash_node<std::pair<const int, Foo>, false> > >’ 
/usr/local/include/c++/5.3.0/bits/hashtable.h:170:11: required from ‘class std::_Hashtable<int, std::pair<const int, Foo>, std::allocator<std::pair<const int, Foo> >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >’ 
/usr/local/include/c++/5.3.0/bits/unordered_map.h:101:18: required from ‘class std::unordered_map<int, Foo>’ 
rh.cpp:4:32: required from here 
/usr/local/include/c++/5.3.0/bits/stl_pair.h:102:11: error: ‘std::pair<_T1, _T2>::second’ has incomplete type 
     _T2 second;    /// @c second is a copy of the second object 
     ^
rh.cpp:3:7: note: forward declaration of ‘class Foo’ 
class Foo { 

nie ma problemu z kodem wykorzystaniem szczęk (testowałem 3.8 na Linux i OSX 3.9):

clang++ --std=c++1y --stdlib=libc++ -c rh.cpp

na Linuksie, używając szczęk + libstdC++ również nie.

Problem wydaje się sprowadzać do wersji libstdC++ przy użyciu __gnu_cxx::__aligned_buffer w implementacji mapy skrótu, która wymaga pełnego typu.

Obie standardowe biblioteki działają poprawnie, gdy używany jest std :: map, ale nie jest to rozwiązanie, które mogę zaakceptować. Nie ma również typu wartości mapy jako wskaźnika do Foo.

Czy są jakieś inne zmiany, które mogę wprowadzić, aby kod działał na gcc/libstdC++?

Dzięki!

+0

Czy umieścisz 'm' w samym wskaźniku? –

+0

to może być podejście, ale nie mogę wymyślić, jak to działa. Kiedy zrobię "m" wskaźnik, gcc jest szczęśliwy, ale gdy tylko spróbuję wywołać nowe w konstruktorze, np. 'Foo(): m (nowy std :: unordered_map ()) {}', mam ten sam problem. – lilinjn

Odpowiedz

0

Proponuję zmodyfikować Foo klasy w następnym sposób:

class Foo { 
public: 
    Foo(); 
private: 
    using MapType = std::unordered_map<std::string, Foo>; 
    std::shared_ptr<MapType> m_ptr; 
}; 

// Here Foo is already defined. 
Foo::Foo() { 
    m_ptr = std::make_shared<MapType>(); 
} 

Ten kod kompiluje grzywny zarówno clang 3.9 i gcc 6.2.

+0

Sam wybrałbym 'unique_ptr', co podkreśliłoby potrzebę napisania niestandardowego konstruktora kopii. – hvd

+0

@hvd Nie zastanawiałem się nad typem ptr, po prostu czymś, co pomaga uniknąć niestandardowego zarządzania pamięcią. W każdym razie głównym pomysłem było pokazanie, jak zmienić kod, aby uniknąć problemów z kompilacją. –