It is an implementation detail, but could you do something nasty with the internal friend declaration:
template<typename _Tp1>
friend void
__enable_shared_from_this_helper(const __shared_count<>& __pn,
const enable_shared_from_this* __pe,
const _Tp1* __px) noexcept
Implement your own version with _Tp1 as weak_ptr<>*, that returns the weak pointer [Actually not quite as __px is a const pointer, so you need an extra indirection to lose the const, or if you are being dirty anyway, cast it away!]
. Wrap it all in a class that you then derive from instead of enable_shared_from_this:
#if >= C++17
using enable_shared_from_this_c17 = enable_shared_from_this;
#else
template<typename _Tp>
enable_shared_from_this_c17: public enable_shared_from_this<_Tp>
{
weak_ptr<_Tp> weak_from_this()
{
weak_ptr<_Tp> rv; auto rv2 = &rv;
__enable_shared_from_this_helper(*(const __shared_count<>*)nullptr, this, &rv2);
return rv;
}
}
#endif
Now, you have an implementation of weak_from_this() in c++14. Yes, it is a nasty cludge, but it is just until you upgrade to 17.
Alternatively, just catch the exception!
Third alternative - add an instantiate template wrapper that sets "constructed" in a wrapper for enable_shared_from_this that wraps shared_from_this() so it fails until the constructed flag has been set.
enable_shared_from_this
safe_shared_from_this
your interfaces
your_implementation
constructed<your_implementation>
Of course, this is imperfect if the class is ever used without immediately assigning to a shared_ptr.