Yes, can you explain what i'm missing, please ?

Let's take the case of make_scoped(new int(1975), normal_struct_fp()). This creates a scoped<int, normal_struct_fp> where m_onLeaveScope_empty is of type normal_struct_fp. And the scoped constructor is trying to assign an object of type default_empty<int> to a variable of type normal_struct_fp. That won't work, just because 2 types have an () operator with the same signature it doesn't mean that you can convert from one type to another.

How would i make it work or is that not a possibility without std::function?

Well, it seems to me that the only purpose of m_onLeaveScope_empty is to support the move constructor. You could leave the old m_onLeaveScope alone and add a null check in the scoped destructor so the old m_onLeaveScope doesn't get called.