我想用自定义赋值运算符编写一个聚合模板结构,如下所示:
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之前,并且不可能将通用代码移至基类)。
还有更好的方法吗?
答案 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进行编译,但是编译器不会使用自继承技术进行投诉。