2016-03-25 32 views
1

我使用curiously recurring template pattern如何在奇怪的循環模板模式中使用基類中的unordered_map?

#include <unordered_map> 

using namespace std; 

template<class S> 
struct State { 
    unordered_map<int, S> children; // <-- problem! 
}; 

struct TicTacToeState : public State<TicTacToeState> { 
    // implementation 
}; 

int main() { 
    return 0; 
} 

基本上,我想有孩子的unordered_map在(基地)國家規定。

編譯g++ file.cpp -std=c++11

In file included from /usr/include/c++/4.8/utility:70:0, 
       from /usr/include/boost/config/no_tr1/utility.hpp:21, 
       from /usr/include/boost/config/select_stdlib_config.hpp:37, 
       from /usr/include/boost/config.hpp:40, 
       from /usr/include/boost/functional/hash/hash_fwd.hpp:17, 
       from /usr/include/boost/functional/hash/hash.hpp:13, 
       from /usr/include/boost/functional/hash.hpp:6, 
       from tests/../examples/tic_tac_toe.cpp:1, 
       from tests/test_tic_tac_toe.cpp:3: 
/usr/include/c++/4.8/bits/stl_pair.h: In instantiation of ‘struct std::pair<const long unsigned int, TicTacToeState>’: 
/usr/include/c++/4.8/type_traits:615:28: required from ‘struct std::__is_destructible_impl<std::pair<const long unsigned int, TicTacToeState> >’ 
/usr/include/c++/4.8/type_traits:637:12: required from ‘struct std::__is_destructible_safe<std::pair<const long unsigned int, TicTacToeState>, false, false>’ 
/usr/include/c++/4.8/type_traits:652:12: required from ‘struct std::is_destructible<std::pair<const long unsigned int, TicTacToeState> >’ 
/usr/include/c++/4.8/type_traits:116:12: required from ‘struct std::__and_<std::is_destructible<std::pair<const long unsigned int, TicTacToeState> >, std::__is_direct_constructible_impl<std::pair<const long unsigned int, TicTacToeState>, const std::pair<const long unsigned int, TicTacToeState>&> >’ 
/usr/include/c++/4.8/type_traits:817:12: required from ‘struct std::__is_direct_constructible_new_safe<std::pair<const long unsigned int, TicTacToeState>, const std::pair<const long unsigned int, TicTacToeState>&>’ 
/usr/include/c++/4.8/type_traits:895:12: [ skipping 5 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ] 
/usr/include/c++/4.8/type_traits:974:12: required from ‘struct std::is_copy_constructible<std::pair<const long unsigned int, TicTacToeState> >’ 
/usr/include/c++/4.8/bits/alloc_traits.h:540:12: required from ‘struct std::__is_copy_insertable<std::allocator<std::pair<const long unsigned int, TicTacToeState> > >’ 
/usr/include/c++/4.8/bits/alloc_traits.h:560:63: required by substitution of ‘template<class _Alloc> using __check_copy_constructible = std::__allow_copy_cons<std::__is_copy_insertable<_Alloc>::value> [with _Alloc = std::allocator<std::pair<const long unsigned int, TicTacToeState> >]’ 
/usr/include/c++/4.8/bits/unordered_map.h:97:11: required from ‘class std::unordered_map<long unsigned int, TicTacToeState, std::hash<long unsigned int>, std::equal_to<long unsigned int>, std::allocator<std::pair<const long unsigned int, TicTacToeState> > >’ 
tests/../examples/../gtsa.hpp:110:30: required from ‘struct State<TicTacToeState, TicTacToeMove>’ 
tests/../examples/tic_tac_toe.cpp:69:32: required from here 
/usr/include/c++/4.8/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 
     ^
In file included from tests/test_tic_tac_toe.cpp:3:0: 
tests/../examples/tic_tac_toe.cpp:69:8: error: forward declaration of ‘struct TicTacToeState’ 
struct TicTacToeState : public State<TicTacToeState, TicTacToeMove> { 
     ^
In file included from /usr/include/c++/4.8/utility:70:0, 
       from /usr/include/boost/config/no_tr1/utility.hpp:21, 
       from /usr/include/boost/config/select_stdlib_config.hpp:37, 
       from /usr/include/boost/config.hpp:40, 
       from /usr/include/boost/functional/hash/hash_fwd.hpp:17, 
       from /usr/include/boost/functional/hash/hash.hpp:13, 
       from /usr/include/boost/functional/hash.hpp:6, 
       from tests/../examples/tic_tac_toe.cpp:1, 
       from tests/test_tic_tac_toe.cpp:3: 
/usr/include/c++/4.8/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&) [with _U1 = long unsigned int&; _U2 = TicTacToeState&; <template-parameter-2-3> = void; _T1 = const long unsigned int; _T2 = TicTacToeState]’: 
tests/../examples/../gtsa.hpp:640:57: required from ‘S* MonteCarloTreeSearch<S, M>::add_child(S*, M&) [with S = TicTacToeState; M = TicTacToeMove]’ 
tests/../examples/../gtsa.hpp:472:41: required from ‘S* MonteCarloTreeSearch<S, M>::tree_policy(S*, S*) [with S = TicTacToeState; M = TicTacToeMove]’ 
tests/../examples/../gtsa.hpp:453:44: required from ‘void MonteCarloTreeSearch<S, M>::monte_carlo_tree_search(S*) [with S = TicTacToeState; M = TicTacToeMove]’ 
tests/../examples/../gtsa.hpp:433:41: required from ‘M MonteCarloTreeSearch<S, M>::get_move(S*) [with S = TicTacToeState; M = TicTacToeMove]’ 
tests/test_tic_tac_toe.cpp:123:1: required from here 
/usr/include/c++/4.8/bits/stl_pair.h:145:64: error: using invalid field ‘std::pair<_T1, _T2>::second’ 
    : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { } 
                   ^

我的理解是:

我要求創建一個struct TicTacToeState,它看起來什麼是基類,啊哈,它的模板,做工精細,它會嘗試使用S = TicTacToeState實例化狀態但失敗,因爲unordered_map<int, S>需要已經爲映射值定義了類型,但未定義TicTacToeState。

將TicTacToeState置於前面不會有幫助,因爲那樣它將沒有國家聲明。

如果有人想對原始代碼有更廣泛的瞭解,State定義爲here。我第一次使用CRTP,也許我不需要它,它只是使代碼複雜化?我不知道,我還沒找到任何簡單的東西。

如何使它工作?

+3

標準庫容器不能保證在不完整的類型下正常工作。嘗試使用'S *'作爲映射類型,它應該可以工作。 – Brian

回答

2

類/結構體不能有不完整類型的成員,所以它們不能引用自己,因爲它們需要自己定義來形成這個類。

由於循環std :: unordered_map應該給你一個參考std::pair<const Key, Value>它需要一個完整的類型。

因此,爲了做這樣的事情,你必須使用一個使用分配的包裝類,允許你首先完成類型並在別處使用它。 在大多數情況下,我會使用std::unordered_map<int, std::unique_ptr<S>>,但如果您確實需要創建元素,則可以將其包裝。

struct SWrapper final 
{ 
    SWrapper(); 
    operator S&() { return *_S; } 
    operator const S&() const { return *_S; } 
private: 
    std::unique_ptr<S> _S; 
}; 

// In .cpp 
SWrapper::SWrapper() : _S(std::make_unique<S>()) {} 
+1

你如何解釋,OP的代碼,如果用地圖替換unordered_map編譯良好? – Christophe

+0

有效點!雖然std :: map是由於它的本質更可能分配它的數據,而std :: unordered_map不是。所有都與您正在使用的STL的實現相關聯。但是,一般來說,我會建議不要在std :: map中使用不完整的類型。 – JVApen

+1

確實:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html – Christophe

相關問題