我有一个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
}