ddc*_*dcc 8 c++ templates metaprogramming
假设我有一些通用代码,我想重用多个类来实现相同的底层功能,但是具有不同成员函数名的接口.例如,如果底层类具有erase
成员函数,则以下代码将起作用,例如std::set
或std::unordered_set
.
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;
}
Run Code Online (Sandbox Code Playgroud)
但是,现在我想让这个函数与例如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);
};
Run Code Online (Sandbox Code Playgroud)
我还尝试用函数模板包装成员函数,如下所示.这似乎是编译,但由于未定义的引用,例如,无法链接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());
Run Code Online (Sandbox Code Playgroud)
我应该如何在编译时执行此别名?我知道我可以提供一个继承自每个底层类的抽象接口的实现,或者使用指向成员函数的指针,但我想避免任何运行时开销.
您可以在辅助结构中提供简单的包装函数以及部分专业化:
template <typename T>
struct set_ops {
static auto erase(T& t, const T::value_type& obj) {
return t.erase(obj);
}
};
template <typename... T>
struct set_ops<tbb::concurrent_unordered_set<T...>> {
using set_type = tbb::concurrent_unordered_set<T...>;
static auto erase(set_type& t, const typename set_type::value_type& obj) {
return t.unsafe_erase(obj);
}
};
Run Code Online (Sandbox Code Playgroud)
那么你的set_inert_time
函数将如下所示:
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_ops<T>::erase(set, v);
end = std::chrono::high_resolution_clock::now();
return end - start;
}
Run Code Online (Sandbox Code Playgroud)
这避免了所有与成员函数指针相关的混乱,并且使所有内容都可以在编译时很好地解决。
归档时间: |
|
查看次数: |
658 次 |
最近记录: |