It would not be a single exercise, but a series, building on top of each other.
The first one could be this:
Define a class called Any in such a way that an object of this class is constructible from objects of any type
The initial code could be just empty.
The test would be like this
int main() {
// test that Any is initializable from any type
Any i = 3;
Any v = std::vector<int>{};
Any l = []{}; // including the untypeable type of a lambda
// test that Any is a hard type, not a template
static_assert(std::is_same_v<decltype(i), decltype(v)>);
static_assert(std::is_same_v<decltype(i), decltype(l)>);
}
and that would essentially ensure that they have written a non-template class with a templated constructor, rather than a template class or anything else.
This is the first step towards a implementation of std::any.
A second step could start from this code:
struct Any {
template<typename T>
requires std::is_lvalue_reference_v<T>
Any(T&& t)
: payload{/* choose initializer here */}
{}
template<typename T>
friend T const* AnyCast(Any& a) {
return static_cast<T const*>(a.payload);
}
private:
/* chose type here */ payload;
};
and ask to declare the payload member variable and initialize it appropriately in the constructor in such a way that AnyCast, if given the type that was passed to Any’s constructor, returns the pointer to that very object.
The test would be along these lines
int main() {
int i{3};
std::vector<int> v{};
auto l = []{};
// test that Any is initializable from any type
Any ai = i;
Any av = v;
Any al = l; // including the untypeable type of a lambda
// test that Any is a hard type, not a template
static_assert(std::is_same_v<decltype(ai), decltype(av)>);
static_assert(std::is_same_v<decltype(ai), decltype(al)>);
assert(&i == AnyCast<int>(ai));
assert(&v == AnyCast<std::vector<int>>(av));
assert(&l == AnyCast<decltype(l)>(al));
}
and would make sure that they have indeed stored a pointer to the object passed to the constructor, and if they have done so, they must have used void*, which is at the heart of type-erasure in C++.
And following exercise would go on like this.