I am writing a class stalker<Obj> that holds inside a variable of type Obj. I want stalker<Obj> to pretend that it is the same as Obj (from the user's perspective). Thus, I expect that stalker<Obj> is constructible like Obj.
template <typename Obj>
class stalker {
Obj obj;
// other variables
public:
template <typename... Args>
stalker(Args&&... args) : obj(std::forward<Args>(args)...) {
}
};
I implement only copy & move constructors additionally.
stalker<Obj> also has other variable(s) which require some specific logiŃ (independent from Obj) when created.
Obj can be marked final.
However, my approach fails on distinguishing std::initialiser_list and curly brackets object. The compiler says: "No matching constructor for initialization of 'std::vector<int>'".
int main() {
stalker<std::vector<int>> v = {1, 2, 3}; // CE
stalker<std::vector<int>> v({1, 2, 3}); // CE
return 0;
}
How to reach stalker<Obj> maximal imitation of Obj in terms of construction?
Creating constructors from const Obj& and Obj&& fails: sometimes the compiler cannot conclude which of these constructors fits the best and in other cases it does not try to adapt {...} -> std::init_list -> Obj at all (just {...} -> Obj).
I added these constructors (is std::is_constructible enough?):
template <typename T>
requires (std::is_constructible_v<Obj, const std::initializer_list<T>&>)
stalker(const std::initializer_list<T>& init_list) : obj(init_list) {
}
template <typename T>
requires (std::is_constructible_v<Obj, std::initializer_list<T>&&>)
stalker(std::initializer_list<T>&& init_list) : obj(std::move(init_list)) {
}
However, now it compiles with std::vector but shows an error (and it does work with the raised error after all!):
struct A {
int val;
};
int main() {
stalker<A> a = {1};
return 0;
}
Also, it does not convert inner {...} to std::initialiser_list.
int main() {
stalker<std::vector<std::vector<int>>> v = {{1, 2, 3, 4},
{5, 6, 7},
{8, 9},
{10}};
return 0;
}