SFINAE 方式...
为简化起见,您可以为无常量 T 添加一个 using 类型
using no_const_T = std::remove_const_t<T>;
当T不是const时等于T,当T是const时不同。
只有当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
}