假設我有一些泛型代碼,我希望爲實現相同底層功能但具有不同成員函數名稱的接口的多個類重用。例如,如果基礎類具有erase
成員函數(例如, std::set
或std::unordered_set
。編譯時在C++中使用別名成員函數
template <typename T>
static std::chrono::duration<double> set_insert_time(const typename T::value_type &v) {
T set;
std::chrono::time_point<std::chrono::high_resolution_clock> start, end;
start = std::chrono::high_resolution_clock::now();
set.erase(v);
end = std::chrono::high_resolution_clock::now();
return end - start;
}
但是,現在我希望此功能可以與例如tbb::concurrent_unordered_set
,它提供了一個名爲unsafe_erase
的函數。
我最初的做法是利用部分模板專業化的類型特徵,通過定義以下內容,並調用set_ops<T>::erase(set, v)
來代替。不幸的是,這不會編譯,因爲 tbb::concurrent_unordered_set
是一個模板類,而不是一個類型。我還嘗試使用第二個鍵類型的模板參數來擴展類型特徵,但由於T
不是std::mem_fn(&T<U>::erase)
中的模板,因此無法編譯。
template <typename T>
struct set_ops {
constexpr static auto erase = std::mem_fn(&T::erase);
};
template <>
struct set_ops<tbb::concurrent_unordered_set> {
constexpr static auto erase = std::mem_fn(&T::unsafe_erase);
};
我也嘗試用函數模板包裝成員函數,如下所示。這似乎是編譯的,但由於未定義的引用而未能鏈接。 decltype ((({parm#1}.erase)({parm#2})),((bool)())) erase<std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int> > >(std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int> >&, std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int> >::key_type const&)
template <typename T>
constexpr auto set_erase(T& s, const typename T::key_type &v) -> decltype(s.erase(v), bool());
template <typename T>
constexpr auto set_erase(T& s, const typename T::key_type &v) -> decltype(s.unsafe_erase(v), bool());
我應該如何在編譯時執行此別名?我知道我可以提供從每個基礎類的抽象接口繼承的實現,或者使用指向成員函數的指針,但是我想避免任何運行時間開銷。
似乎過於複雜。兩個版本的'erase'可以是自由函數,通過重載分辨率來選擇。 – MSalters
@MSalters這是ether部分專業化或'enable_if' SFINE技巧。否則,最終會出現'erase(tbb :: concurrent_unordered_set&,const tbb :: concurrent_unordered_set :: value_type&)'的模糊重載。 –