当前位置: 首页 > 知识库问答 >
问题:

C++条件模板构造函数

元修然
2023-03-14

我有一个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 应该合法,但handleid =handleid 不应该合法。

现在,我想添加一个模板,专门化或其他东西,但我肯定有一个更好的方法来做这件事。请注意,非常量版本必须将常量版本添加为友元,才能访问constructor/assignmnent运算符中的私有成员。

共有1个答案

雍嘉勋
2023-03-14

斯菲纳伊的方式...

为了简化,可以为no-constt添加using类型

using no_const_T = std::remove_const_t<T>;

t不是常量时,这等于t;当t常量时,则不同。

那么只有当tno_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