如何使用另一个类作为类模板专用化
How to use another class as a class template specialization
我有一个混合锁类,它在返回到std::mutex
上的阻塞之前,对一个锁进行旋转尝试(编译时固定)多次旋转,直到该锁可用。
简化:
#include <mutex>
template<unsigned SPIN_LIMIT>
class hybrid_lock {
public:
void lock(){
for(unsigned i(0);i<SPIN_LIMIT;++i){
if(this->mMutex.try_lock()){
return;
}
}
this->mMutex.lock();
}
void unlock(){
this->mMutex.unlock();
}
private:
std::mutex mMutex;
};
在SPIN_LIMIT==0
的特殊情况下,这又回到了"普通"std::mutex
(即没有可见的自旋)。
所以我把它专门用于:
template<>
class hybrid_lock<0> : public std::mutex {};
它工作得很好,但这是将类模板专门化为另一个(预先存在的)模板的批准方式吗?
注意:我回答的是实际问题,而不是标题中的问题。
好吧,现在hybird_lock<0>
和hybird_lock<1>
有很大的不同,一个来源于std::mutex
,另一个包含/包装它。这改变了hybird_lock
的整个组成及其背后的含义。也就是说,它们在语义上不相同。这可能会导致一些意想不到的后果——hybird_lock<0>
会继承很多其他情况下不会有的东西。
如果这是唯一的区别的话,我根本不会去关注专业化。请记住,零情况在编译时是已知的,当然,整个循环将完全优化。
如果还有其他重要的(或实际的)优化,我会选择这样的优化:
template<>
class hybrid_lock<0> {
public:
void lock(){
this->mMutex.lock();
}
void unlock(){
this->mMutex.unlock();
}
private:
std::mutex mMutex;
};
这种实现使0
成为一种特殊情况,而不是几乎完全不同的情况。
没有"官方"方法可以做到这一点,但这里有一个好方法-对于模板,最好将主模板类分解为较小的"action"或"function"模板类。通过这种方式,你可以对专业化进行更多的控制和粒度控制,这意味着你只需要在一个地方维护主要逻辑:
#include <iostream>
#include <mutex>
// general form of the spin_locker
template<unsigned SPIN_LIMIT, class Mutex>
struct spinner
{
static void lock(Mutex& m) {
for (unsigned i = 0 ; i < SPIN_LIMIT ; ++i)
if (m.try_lock())
return;
m.lock();
}
};
// optmised partial specialisation for zero spins
template<class Mutex>
struct spinner<0, Mutex>
{
static void lock(Mutex& m) {
m.lock();
}
};
template<unsigned SPIN_LIMIT, class Mutex = std::mutex>
class hybrid_lock {
using spinner_type = spinner<SPIN_LIMIT, Mutex>;
public:
void lock(){
spinner_type::lock(mMutex);
}
void unlock(){
mMutex.unlock();
}
std::unique_lock<Mutex> make_lock() {
return std::unique_lock<Mutex>(mMutex);
}
private:
Mutex mMutex;
};
// since only the 'spinner' functor object needs specialising there is now no need to specialise the main logic
using namespace std;
auto main() -> int
{
hybrid_lock<100> m1;
hybrid_lock<0> m2;
hybrid_lock<100, std::recursive_mutex> m3;
hybrid_lock<0, std::recursive_mutex> m4;
auto l1 = m1.make_lock();
auto l2 = m2.make_lock();
auto l3 = m3.make_lock();
auto l4 = m4.make_lock();
return 0;
}
Richard Hodges的答案很好,但您可以简单地重载方法lock
:
#include <iostream>
#include <type_traits>
#include <mutex>
template<class Mutex = std::mutex>
struct hybrid_lock {
template<int N>
void lock(std::integral_constant<int, N> val){
for (unsigned i = 0 ; i < val() ; ++i)
if (mMutex.try_lock())
return;
mMutex.lock();
}
void lock(std::integral_constant<int, 0>){
mMutex.lock();
}
void unlock(){
mMutex.unlock();
}
std::unique_lock<Mutex> make_lock() {
return std::unique_lock<Mutex>(mMutex);
}
private:
Mutex mMutex;
};
template <int N>
constexpr
std::integral_constant<int, N> IC;
int main() {
hybrid_lock<> m1;
hybrid_lock<> m2;
m1.lock(IC<0>);
m2.lock(IC<100>);
return 0;
}
IC是一个可变模板,从c++14开始,如果你的编译器不支持它,你可以使用类型别名类型别名:
template<int N>
using IC = std::integral_constant<int, N>;
并像这个一样使用它
m.lock(IC<0>{});
相关文章:
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 使用其他模板的模板专用化
- 使用专用显卡进行 OpenGL 渲染时帧速率较低
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 使用对象的基类部分模板专用化对对象进行哈希处理::哈希
- 在部分模板专用化中使用 decltype
- 使用限定名称的部分专用化
- 如何使用 STL 排序对具有模板专用化的自定义类对象进行排序?
- 成员变量如何使用专用类模板?
- 检查类是否具有模板专用化(使用布尔值或 int 等模板参数)
- 使用 C++20 概念模板函数专用化时的依赖项
- 使用类模板的内部类模板专用化模板
- 使用类指针重载C++命名空间函数模板专用化替代方法?
- 使用模板模板参数进行模板定义的函数专用化
- 在模板专用化中使用非类型模板模板参数
- 使用模板专用化来比较指针引用
- 使用类型特征的部分类专用化
- 在部分模板专用化中使用括号
- 部分专用化:使用主模板成员
- 为什么不允许非类型参数中的部分专用化使用嵌套模板参数