INTRO
I am writing a class stalker<Obj> that holds inside a variable of type Obj. I want that stalker<Obj> to pretend that it is almost the same as Obj variable (from the user's perspective). However, we hardly know anything about Obj.
So, I try to achieve this by overloading all possible operators (except for literal ones) and I also overload cast operator for the other unexpected behavior. This creates a lot of code:
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...
};
The first problem is that Obj::operator[] can be returning void. I do not want to duplicate my code. Here is how i solved it:
EDIT: there is no need for this (see the discussion below)
// useless invention
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)];
}
}
This code already looks heavy (do you know a simpler way?).
PROBLEM
stalker<Obj> can be tagged as const or it has a const type: stalker<const Obj>. Then we need const versions of all our operators.
How can we templately overload a void/non-void and const/non-const operators in one declaration inside a class?
Or is there a better way to achieve stalker<Obj> behaviour identical to Obj?
APPROACHES
CPP Reference has: non-duplicate code of both const & non-const versions (help me to understand this).
Another website provides: https://www.cppstories.com/2020/11/share-code-const-nonconst.html/. However, mutable qualifier or const_cast are not a solution. I hardly understand the part with templates but it seems that in this way we are not pretending as Obj anymore (we need to pass obj in some function).

It is not a problem, returning
voidis valid.is ok.
As seen above, void/non-void is no problematic. There are still const/volatile and reference cartesion product overloads though.
Before C++23, you have to write all of them.
Since C++23, there is "deducing
this" which allows to write justYou might SFINAE your method and use same
noexceptto mimic more the type: