如何专门化模板 class 中的赋值运算符?
How to specialize assignment operator in template class?
我想用自定义赋值运算符编写一个聚合模板结构,如下所示:
template <typename T>
struct Foo {
Foo() = default;
Foo(const Foo&) = default;
Foo& operator=(const Foo& f) { ... }
...
};
现在,如果 T
是我想要的 const 限定类型:
Foo& operator=(const Foo& f) = delete;
我能想到的唯一方法是专门化 Foo
struct:
template<T> struct Foo<const T> {
Foo& operator=(const Foo& f) = delete;
... a lot of code ...
}
但是为了专门化这个结构,我必须复制粘贴所有剩余的代码(聚合意味着没有继承 - 至少在 C++17 之前,并且不可能将公共代码移动到基础 class)。
有更好的方法吗?
我提出一种自继承:从通用版本继承的const特化
template <typename T>
struct Foo
{
Foo() = default;
Foo(Foo const &) = default;
Foo& operator= (Foo const & f) { return *this; }
};
template <typename T>
struct Foo<T const> : public Foo<T>
{
Foo& operator= (Foo const & f) = delete;
};
这样,您的 const 特化继承了通用版本的所有内容,因此无需复制和过去所有通用代码,除了被删除的 operator=()
。
下面是一个完整的例子
template <typename T>
struct Foo
{
Foo() = default;
Foo(Foo const &) = default;
Foo& operator= (Foo const & f) { return *this; }
};
template <typename T>
struct Foo<T const> : public Foo<T>
{
Foo& operator=(Foo const & f) = delete;
};
int main ()
{
Foo<int> fi;
Foo<int const> fic;
fi = fi; // compile
// fic = fic; // compilation error
}
我认为您可以使用 CRTP 完全隐藏分配。在结构上,它类似于,但它使用静态多态性在基类中实现赋值运算符。 const
专用版本已删除,因此尝试调用赋值运算符将失败。
template <typename D>
struct FooCRTP {
D & derived () { return *static_cast<D *>(this); }
D & operator = (const D &rhs) { return derived() = rhs; }
};
template <typename T> struct Foo : FooCRTP<Foo<T>> {};
template <typename T>
struct Foo<const T> : FooCRTP<Foo<const T>>
{
Foo & operator = (const Foo &) = delete;
};
CRTP 版本相对于自继承技术的一个优点是,在 CRTP 解决方案中,基本 class 赋值是使用派生的赋值实现的。然而,在自继承技术中,base class 赋值是它自己的实现,因此它可能会被意外调用。例如:
Foo<int> f_int;
Foo<const int> f_cint;
f_cint.Foo<int>::operator=(f_int);
以上代码将无法通过 CRTP 进行编译,但编译器不会因使用自继承技术而报错。
我想用自定义赋值运算符编写一个聚合模板结构,如下所示:
template <typename T>
struct Foo {
Foo() = default;
Foo(const Foo&) = default;
Foo& operator=(const Foo& f) { ... }
...
};
现在,如果 T
是我想要的 const 限定类型:
Foo& operator=(const Foo& f) = delete;
我能想到的唯一方法是专门化 Foo
struct:
template<T> struct Foo<const T> {
Foo& operator=(const Foo& f) = delete;
... a lot of code ...
}
但是为了专门化这个结构,我必须复制粘贴所有剩余的代码(聚合意味着没有继承 - 至少在 C++17 之前,并且不可能将公共代码移动到基础 class)。
有更好的方法吗?
我提出一种自继承:从通用版本继承的const特化
template <typename T>
struct Foo
{
Foo() = default;
Foo(Foo const &) = default;
Foo& operator= (Foo const & f) { return *this; }
};
template <typename T>
struct Foo<T const> : public Foo<T>
{
Foo& operator= (Foo const & f) = delete;
};
这样,您的 const 特化继承了通用版本的所有内容,因此无需复制和过去所有通用代码,除了被删除的 operator=()
。
下面是一个完整的例子
template <typename T>
struct Foo
{
Foo() = default;
Foo(Foo const &) = default;
Foo& operator= (Foo const & f) { return *this; }
};
template <typename T>
struct Foo<T const> : public Foo<T>
{
Foo& operator=(Foo const & f) = delete;
};
int main ()
{
Foo<int> fi;
Foo<int const> fic;
fi = fi; // compile
// fic = fic; // compilation error
}
我认为您可以使用 CRTP 完全隐藏分配。在结构上,它类似于const
专用版本已删除,因此尝试调用赋值运算符将失败。
template <typename D>
struct FooCRTP {
D & derived () { return *static_cast<D *>(this); }
D & operator = (const D &rhs) { return derived() = rhs; }
};
template <typename T> struct Foo : FooCRTP<Foo<T>> {};
template <typename T>
struct Foo<const T> : FooCRTP<Foo<const T>>
{
Foo & operator = (const Foo &) = delete;
};
CRTP 版本相对于自继承技术的一个优点是,在 CRTP 解决方案中,基本 class 赋值是使用派生的赋值实现的。然而,在自继承技术中,base class 赋值是它自己的实现,因此它可能会被意外调用。例如:
Foo<int> f_int;
Foo<const int> f_cint;
f_cint.Foo<int>::operator=(f_int);
以上代码将无法通过 CRTP 进行编译,但编译器不会因使用自继承技术而报错。