I actually had similar problems many years ago when I had vector<unique_ptr<T>> and API was taking const vector<const T*>& , so this trick worked fine :).
This is closely related to the ideas of
- is_trivially_constructible_from<T, U>
- is_trivially_swappable_with<T, U>
- is_trivially_relocatable_from<T, U>
The idea is that since
using T = std::unique_ptr<int>;
using U = int*;
void construct(T *dst, U *src) {
::new (dst) T(*src);
}
can be accomplished by a memcpy, then is_trivially_constructible_from<T, U> can be true.
However, the thing in this thread is yet again different: it's kind of like `is_trivially_const_referenceable_as<T, U>`.
The problem is, I don't see how the compiler could ever infer this kind of thing for user-defined types. It could be achievable for primitive types, e.g. the compiler could tell us that `__is_trivially_const_referenceable_as(int, long)` on appropriate platforms. But that's not useful for programmers. And even with an attribute or something, it doesn't seem ergonomic (or even possible at all, really) for someone to write
template<class T>
struct [[trivially_constructible_from(T*)]] unique_ptr {
explicit unique_ptr(T *p) : p_(p) {}
T *p_;
};
because it would be a combinatorial explosion — there are many types, an open-ended set of (possibly user-defined) types, that our unique_ptr might be trivially-constructible-from.
–Arthur