C++ 基于模板的条件类成员

C++ 基于模板的条件类成员,c++,c++17,C++,C++17,我想让一个接收互斥类型作为模板参数的类(有条件地)是线程安全的。如果互斥类型等于NoMutex(我的互斥空实现),我不想将这个互斥成员添加到我的类中,这样可以节省空间。 我想这样做: classnomutex{ //与std::mutex接口相同,但实现为空 //因此,优化可以删除不必要的函数调用 }; 模板 类MyClass{ 公众: //实际上,我想以某种方式隐藏它。如果Mutex==NoMutex,我不希望它占用任何空间 一些_-template _-trick您可以使用包含一个或两个内容

我想让一个接收互斥类型作为模板参数的类(有条件地)是线程安全的。如果互斥类型等于NoMutex(我的互斥空实现),我不想将这个互斥成员添加到我的类中,这样可以节省空间。 我想这样做:

classnomutex{
//与std::mutex接口相同,但实现为空
//因此,优化可以删除不必要的函数调用
};
模板
类MyClass{
公众:
//实际上,我想以某种方式隐藏它。如果Mutex==NoMutex,我不希望它占用任何空间

一些_-template _-trick您可以使用包含一个或两个内容(未经测试的代码)的结构包装器来实现这一点:

模板类对{
配对(常数T1和T1,常数T2和T2):T1_(T1),T2_(T2){}
T1&first(){return T1_;}
T2&second(){return T2_;}
T1;
T2;
};
模板类对{
配对(常数T1&T1):T1_uz(T1){}
T1&first(){return T1_;}
NoMutex second(){return NoMutex();}
T1;
};

空数据成员可以使用空基类优化(EBO)进行优化。也就是说,尽管无状态类的大小不为零(至少为1字节),但如果用作基类,它不会消耗额外的内存:

模板
struct CompressedMutex
{
互斥互斥;
Mutex&getMutex(){return Mutex;}
};
模板
struct CompressedMutex:NoMutex
{
NoMutex&getMutex(){return*this;}
};
模板
类别MyClass:压缩型MUTEX
{
公众:
void函数()
{
std::unique_lock l(this->getMutex());
}
};

请注意,当访问作为从属名称的
getMutex()
时,需要
this->
CompressedMutex::


然而,通常情况下,在
const
限定的成员函数中也需要锁定互斥体。为此,可以在互斥体数据成员的定义中使用
mutable
关键字。在
NoMutex
情况下,需要使用
const\u cast(*this)
,或声明返回的
静态
对象:

模板
struct CompressedMutex
{
可变互斥;
Mutex&getMutex()常量{return Mutex;}
};
模板
struct CompressedMutex
{
静态NoMutex互斥;
NoMutex&getMutex()常量{return mutex;}
};

此技术已在标准库中广泛使用,因此无状态分配器(包括
std::allocator
)不占容器的总大小。此类对象通常存储在所谓的压缩对中(例如)或其变体,有时与非空数据成员一起使用,以便封闭类的接口不会更改:

#包括
模板
类MyClass
{
公众:
void函数()
{
std::unique_lock l(data.second());
}
私人:
boost::压缩的_对数据;
};

但如果我将这个Pair类添加到MyClass中,它将始终至少占用一个字节。它怎么可能不占用任何字节?@MasterID:您将类的其他一些成员作为另一个
Pair
参数。为什么在使用NoMutex时仍要创建std::unique_锁?否则我必须复制someFunction实现if constexpr和else内部的函数。我可以编写另一个函数并在if/else内部调用它(每次一次)。但我真正想知道的是,是否可以有条件地将数据成员添加到类中,就像可以添加仅在给定某种类型时才可编译的代码一样。完美!是否需要可变?
template <class T1, class T2> class Pair {
   Pair (const T1 &t1, const T2 &t2) : t1_(t1), t2_(t2) {}
   T1 & first () { return t1_; }
   T2 & second () { return t2_; }

   T1 t1_;
   T2 t2_;
};

template <class T1> class Pair<T1, NoMutex> {
   Pair (const T1 &t1) : t1_(t1) {}
   T1 & first () { return t1_; }
   NoMutex second () { return NoMutex(); }

   T1 t1_;
};