假设我有一些泛型代码,我希望为实现相同底层功能但具有不同成员函数名称的接口的多个类重用。例如,如果基础类具有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&)'的模糊重载。 –