如何在模板类中专门化赋值运算符?

时间:2018-08-06 19:35:21

标签: c++ c++11 templates c++14 template-specialization

我想用自定义赋值运算符编写一个聚合模板结构,如下所示:

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结构:

template<T> struct Foo<const T> {
   Foo& operator=(const Foo& f) = delete;
   ... a lot of code ...
}

但是要专门化此结构,我必须复制-粘贴所有剩余的代码(聚合意味着没有继承-至少在C ++ 17之前,并且不可能将通用代码移至基类)。

还有更好的方法吗?

2 个答案:

答案 0 :(得分:7)

我提出了一种自我继承:从通用版本继承的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
 }

答案 1 :(得分:2)

我认为您可以使用CRTP完全隐藏作业。从结构上讲,它与self-inheritance technique类似,但是它使用静态多态性在基础中实现赋值运算符。 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解决方案中,基类分配是使用派生的分配来实现的。但是,在自继承技术中,基类分配是其自己的实现,因此可能会意外调用它。例如:

Foo<int> f_int;
Foo<const int> f_cint;

f_cint.Foo<int>::operator=(f_int);

以上代码将无法使用CRTP进行编译,但是编译器不会使用自继承技术进行投诉。