简介
我正在编写一个类
stalker<Obj>
,其中包含类型为 Obj
的变量。我希望 stalker<Obj>
假装它与 Obj
变量几乎相同(从用户的角度来看)。然而,我们对Obj
几乎一无所知。
因此,我尝试通过重载所有可能的运算符(文字运算符除外)来实现此目的,并且还针对其他意外行为重载强制转换运算符。这会创建很多代码:
template <typename Obj>
class stalker {
Obj obj;
public:
operator Obj&() {
return obj;
}
template <typename Arg>
decltype(auto) operator[](Arg&& arg) {
return obj[std::forward<Arg>(arg)];
}
// and other 20+ overloads...
};
第一个问题是
Obj::operator[]
可以返回void
。 我不想重复我的代码。这是我解决它的方法:
template <typename Arg>
decltype(auto) operator[](Arg&& arg) {
if constexpr (std::is_same_v<void, decltype(std::declval<Obj&>()[std::forward<Arg>(arg)])>) {
obj[std::forward<Arg>(arg)];
} else {
return obj[std::forward<Arg>(arg)];
}
}
这段代码看起来已经很重了(你知道更简单的方法吗?)。
问题
stalker<Obj>
可以标记为 const
或者它具有 const
类型:stalker<const Obj>
。然后我们需要所有运算符的 const
版本。
我们如何在
one声明 inside 类中模板重载
void
/
non-void
和 const
/non-const
运算符?
或者是否有更好的方法来实现与
stalker<Obj>
相同的 Obj
行为?
方法
另一个网站提供:https://www.cppstories.com/2020/11/share-code-const-nonconst.html/。但是,
mutable
限定符或 const_cast
不是解决方案。我几乎不理解模板部分,但似乎通过这种方式我们不再假装为Obj
(我们需要在某些函数中传递obj
)。
第一个问题是 Obj::operator[] 可能返回 void。
没问题,返回
void
有效。
template <typename Arg>
decltype(auto) operator[](Arg&& arg) { return obj[std::forward<Arg>(arg)]; }
还可以。
我们如何在类内的一个声明中模板地重载 void/non-void 和 const/non-const 运算符?
如上所示,void/non-void 没有问题。 尽管如此,仍然存在 const/volatile 和参考 cartesion 产品重载。
C++23之前,你必须全部编写。
自 C++23 起,就有了“推导
this
”,它允许只写
template <typename Self, typename Arg>
decltype(auto) foo(this Self&& self, Arg&& arg) {
return std::forward<Self>(self).obj[std::forward<Arg>(arg)];
}