[英]Wrapping a recursive variadic template class changes behavior. Why?
希望這會激起社區中的一些人的興趣。 希望它不是太明顯,因為我不確定發生了什么。 我創建了帶有遞歸定義的可變參數模板類,主要是作為一個有趣的自我挑戰。 有點像元組一樣,這個類創建unordered_maps的unordered_maps,任意深度,每層都有任意鍵類型。 例如,您可以創建nested_map<int, std::string, float, int>
,然后使用map["fred"][3.4][42] = 35;
設置它map["fred"][3.4][42] = 35;
這是代碼 - 不是太瘋狂。
template<typename T, typename K, typename ... KS> struct nested_map_base : std::unordered_map<K, T>
{
T &operator[](const K &key)
{
// just to verify we get to the bottom of things recursively
std::cout << "base: key = " << key << std::endl;
return this->std::unordered_map<K, T>::operator[](key);
}
};
template<typename T, typename New_K, typename K, typename ... KS>
struct nested_map_base<T, New_K, K, KS ...>
: std::unordered_map<New_K, nested_map_base<T, K, KS...>>
{
nested_map_base<T, K, KS...> &operator[](const New_K &new_key)
{
// just for debugging and to demonstrate that it's working
// for purposes of this question
std::cout << "midway: key = " << new_key << std::endl;
return this->std::unordered_map<New_K, nested_map_base<T, K, KS...>>::operator[](new_key);
}
};
工作正常。 運行以下代碼,得到預期的輸出 -
std::cout << "Method1:" << std::endl << std::endl;
nested_map_base<int, std::string, double, int> test_nest;
std::cout << "insert" << std::endl;
test_nest["leonard"][4.8][45] = 111;
std::cout << "retrieve" << std::endl;
int &answer = test_nest["leonard"][4.8][45];
std::cout << "Aanswer should be 111. Answer is " << answer << std::endl << std::endl;
生產 -
Method1:
insert
midway: key = leonard
midway: key = 4.8
base: key = 45
retrieve
midway: key = leonard
midway: key = 4.8
base: key = 45
Aanswer should be 111. Answer is 111
整齊。 然后我想我想將它包裝在外部類中以保持實現私有,所以我就這樣開始 -
template<typename datum_type, typename ... keys> class nested_map
{
private:
nested_map_base<datum_type, keys ...> backing_store;
public:
template<typename Base_key, typename ... KS> auto operator[](const Base_key &key)
{
return backing_store[key];
}
};
沒有什么,並且起初它似乎工作,但以下代碼產生不同的結果 -
std::cout << "Method2:" << std::endl << std::endl;
nested_map<int, std::string, double, int> test_nest;
std::cout << "insert" << std::endl;
test_nest["leonard"][4.8][45] = 111;
std::cout << "retrieve" << std::endl;
int &answer = test_nest["leonard"][4.8][45];
std::cout << "Answer should be 111. Answer is " << answer << std::endl << std::endl;
它產生了這個 -
Method2:
insert
midway: key = leonard
midway: key = 4.8
base: key = 45
retrieve
midway: key = leonard
midway: key = 4.8
base: key = 45
Answer should be 111. Answer is 0
遞歸可變參數模板元編程充滿了陷阱,並且有理由不會經常包裝,所以我並不感到震驚的是包裹的那個不起作用,但讓我感到驚訝的是它怎么沒有工作。 它按預期遞歸,直到包含終端基准類型的std::unordered_map
。 在調試器中,從終端映射中恢復了對int的引用,並且在簡單測試代碼中將其設置為111。 您第二次看到鍵被遞歸的事實表明檢索過程似乎也在起作用,但引用的是零值int。 好奇。
我正在深入挖掘調試器,以查看,例如,集合引用的實際地址值是否與用於檢索的引用相同。 我認為它們可能不同的唯一方法是,例如,倒數第二個遞歸層返回最后一層的臨時值,而不是引用數據結構中的那個。 或者也許在包裝的情況下,它們都是臨時的而不是參考......類似的東西,但包裝是如此輕,似乎不可能。 所以如果我發現更多內容,我會添加評論,但我想我會把它扔給社區,看看是否有一些不同的眼睛可以通過檢查來挑逗。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.