如何专门化模板 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 进行编译,但编译器不会因使用自继承技术而报错。