我有一个handleid
类,它的操作类似于智能指针。以下是重要的比特:
template<class T>
class HandleID
{
// Only if T is not const
friend class HandleID<const T>;
public:
HandleID();
HandleID(int id);
HandleID(const HandleID<T>& other);
HandleID& operator=(const HandleID<T>& other);
// Only if T is const
HandleID(const HandleID<const removed T>& other);
HandleID& operator=(const HandleID<const removed T>& other);
private:
T* cachedPointer;
int id;
};
现在,我希望能够从handleid
构造handleid
,而不是相反。复制赋值运算符也是这样:handleid
应该合法,但handleid
不应该合法。
现在,我想添加一个模板,专门化或其他东西,但我肯定有一个更好的方法来做这件事。请注意,非常量版本必须将常量版本添加为友元,才能访问constructor/assignmnent运算符中的私有成员。
斯菲纳伊的方式...
为了简化,可以为no-constt
添加using
类型
using no_const_T = std::remove_const_t<T>;
当t
不是常量
时,这等于t
;当t
是常量
时,则不同。
那么只有当t
和no_const_t
不同时,SFINAE才能启用构造函数/运算符
template <typename U = T,
std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
HandleID(const HandleID<no_const_T> & other);
template <int..., typename U = T,
std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
HandleID& operator=(const HandleID<no_const_T>& other);
注意,您必须检查t
是否与no_const_t
相等或不同,而不是直接使用t
而是使用t
初始化的本地(方法的)模板参数(u
)。
--编辑--
OP询问
当我想要分离声明(您提供的那个)和实现(例如,在文件中更低的类之外)时,语法是什么
是精神错乱。
下面是一个在类主体外部实现的支持SFINAE的方法的完整编译(愚蠢的)示例。
#include <type_traits>
template <typename T>
class HandleID
{
friend class HandleID<T const>;
using no_const_T = std::remove_const_t<T>;
public:
HandleID () {}
HandleID (int) {}
HandleID (HandleID<T> const &) {}
template <typename U = T,
std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
HandleID (HandleID<no_const_T> const &);
HandleID & operator= (HandleID<T> &)
{ return *this; }
template <int..., typename U = T,
std::enable_if_t<not std::is_same_v<U, no_const_T>, int> = 0>
HandleID & operator= (HandleID<no_const_T> const &);
};
template <typename T>
template <typename U,
std::enable_if_t<not std::is_same_v<U,
std::remove_const_t<T>>, int>>
HandleID<T>::HandleID (HandleID<std::remove_const_t<T>> const &)
{ }
template <typename T>
template <int..., typename U,
std::enable_if_t<not std::is_same_v<U,
std::remove_const_t<T>>, int>>
HandleID<T> & HandleID<T>::operator=
(HandleID<std::remove_const_t<T>> const &)
{ return *this; }
int main()
{
HandleID<int> id0;
HandleID<int const> idc0;
HandleID<int> id1{id0}; // copy constructor: compile
//HandleID<int> id2{idc0}; // constructor disabled: compilatrion error
HandleID<int const> idc1{idc0}; // copy constructor: compile
HandleID<int const> idc2{id0}; // constructor enabled: compile
}
主要内容:1、实例构造函数,2、静态构造函数,3、私有构造函数在 C# 中,构造函数就是与类(或结构体)具有相同名称的成员函数,它在类中的地位比较特殊,不需要我们主动调用,当创建一个类的对象时会自动调用类中的构造函数。在程序开发的过程中,我们通常使用类中的构造函数来初始化类中的成员属性。 C# 中的构造函数有三种: 实例构造函数; 静态构造函数; 私有构造函数。 1、实例构造函数 构造函数是类中特殊的成员函数,它的名称与它所在类的名称相同,并且没有返回值。当
主要内容:构造函数的重载,默认构造函数在 C++中,有一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户显式调用(用户也不能调用),而是在创建对象时自动执行。这种特殊的成员函数就是 构造函数(Constructor)。 在《 C++类成员的访问权限以及类的封装》一节中,我们通过成员函数 setname()、setage()、setscore() 分别为成员变量 name、age、score 赋值,这样做虽然有效,但显得有点
我用模板复制构造函数写了一段代码,以便更好地理解这个概念,因为我是新手,但是下面的代码无法编译 在Visual Studio中编译上述代码时出现以下错误:- 错误:- 严重性代码描述项目文件行抑制状态错误C2558类“网格”:没有可用的复制构造函数或复制构造函数被声明为“显式” 我试图用E替换参数的模板,但它显示了更多的错误(奇怪的错误) 错误: 严重性代码描述项目文件行抑制状态错误LNK2019
我有一个模板参数为T的类template Templ,Templ类有一个类型为T的数据成员,称为obj。我编写了一个可变构造函数模板,将参数转发给obj的构造函数: 现在我意识到类型T可能是一个具有init list构造函数的类,我希望它可以通过temp访问。所以我检查了什么是std::list::emplace和make\u shared。它们有一个像我一样的可变函数,但它们没有采用初始化列表的
主要内容:默认拷贝构造函数拷贝和复制是一个意思,对应的英文单词都是 。 对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。 在 C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对
C++ 类 & 对象 类的构造函数 类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。 下面的实例有助于更好地理解构造函数的概念:#include <iostream> using namespace std; class Line { public: v